001package gudusoft.gsqlparser.resolver2.model;
002
003import gudusoft.gsqlparser.nodes.TObjectName;
004import gudusoft.gsqlparser.nodes.TTable;
005import gudusoft.gsqlparser.resolver2.matcher.INameMatcher;
006import gudusoft.gsqlparser.resolver2.matcher.DefaultNameMatcher;
007
008import java.util.*;
009
010/**
011 * Global context for resolution results.
012 * Provides efficient querying and statistics about resolved columns.
013 *
014 * Design principles:
015 * 1. Reverse indexing for O(1) queries
016 * 2. Categorized storage for quick access to different resolution states
017 * 3. Statistics for monitoring resolution quality
018 */
019public class ResolutionContext {
020
021    // === Core storage: forward mapping ===
022
023    /** All processed column references -> resolution results */
024    private final Map<TObjectName, ResolutionResult> resolutions = new LinkedHashMap<>();
025
026    // === Reverse indexes for efficient queries ===
027
028    /** Table -> all columns referencing that table */
029    private final Map<TTable, List<TObjectName>> tableReferences = new HashMap<>();
030
031    /** Column name -> all column references with that name (for conflict detection) */
032    private final Map<String, List<TObjectName>> columnNameIndex = new HashMap<>();
033
034    // === Categorized lists for quick access ===
035
036    /** Exactly matched columns (EXACT_MATCH) */
037    private final List<TObjectName> exactMatches = new ArrayList<>();
038
039    /** Ambiguous columns (AMBIGUOUS) */
040    private final List<TObjectName> ambiguousColumns = new ArrayList<>();
041
042    /** Unresolved columns (NOT_FOUND) */
043    private final List<TObjectName> unresolvedColumns = new ArrayList<>();
044
045    // === Statistics ===
046
047    /** Table reference counts */
048    private final Map<TTable, Integer> tableReferenceCounts = new HashMap<>();
049
050    /** Total column references processed */
051    private int totalColumnReferences = 0;
052
053
054    // ===== Internal methods: called by NameResolver =====
055
056    /**
057     * Register a resolution result.
058     * Called by NameResolver when a column is resolved.
059     */
060    public void registerResolution(TObjectName objName, ResolutionResult result) {
061        // 1. Forward storage
062        resolutions.put(objName, result);
063        totalColumnReferences++;
064
065        // 2. Update reverse index by column name
066        String columnName = objName.getColumnNameOnly();
067        if (columnName != null) {
068            columnNameIndex.computeIfAbsent(columnName, k -> new ArrayList<>())
069                          .add(objName);
070        }
071
072        // 3. Categorize by status
073        switch (result.getStatus()) {
074            case EXACT_MATCH:
075                exactMatches.add(objName);
076                ColumnSource source = result.getColumnSource();
077                if (source != null) {
078                    updateTableReference(source.getFinalTable(), objName);
079                }
080                break;
081
082            case AMBIGUOUS:
083                ambiguousColumns.add(objName);
084                // For ambiguous: all candidates count as references
085                AmbiguousColumnSource ambiguous = result.getAmbiguousSource();
086                if (ambiguous != null) {
087                    for (ColumnSource candidate : ambiguous.getCandidates()) {
088                        updateTableReference(candidate.getFinalTable(), objName);
089                    }
090                }
091                break;
092
093            case NOT_FOUND:
094                unresolvedColumns.add(objName);
095                break;
096        }
097    }
098
099    /**
100     * Update table reference index
101     */
102    private void updateTableReference(TTable table, TObjectName objName) {
103        if (table == null) return;
104
105        // Reverse index
106        tableReferences.computeIfAbsent(table, k -> new ArrayList<>())
107                      .add(objName);
108
109        // Reference count
110        tableReferenceCounts.merge(table, 1, Integer::sum);
111    }
112
113
114    // ===== Public query API (Level 2 API) =====
115
116    /**
117     * Get all column references to a specific table.
118     * Complexity: O(1)
119     *
120     * @param table Target table
121     * @return List of TObjectName referencing that table
122     */
123    public List<TObjectName> getReferencesTo(TTable table) {
124        return tableReferences.getOrDefault(table, Collections.emptyList());
125    }
126
127    /**
128     * Get all column references to a specific table.column.
129     * Complexity: O(m) where m = number of references to the table
130     *
131     * @param table Target table
132     * @param columnName Target column name
133     * @return List of matching TObjectName
134     */
135    public List<TObjectName> getReferencesTo(TTable table, String columnName) {
136        INameMatcher matcher = new DefaultNameMatcher();
137
138        return getReferencesTo(table).stream()
139            .filter(obj -> {
140                String colName = obj.getColumnNameOnly();
141                return colName != null && matcher.matches(colName, columnName);
142            })
143            .collect(java.util.stream.Collectors.toList());
144    }
145
146    /**
147     * Find all column references with a given name (for conflict detection).
148     * Complexity: O(1)
149     */
150    public List<TObjectName> getColumnsByName(String columnName) {
151        return columnNameIndex.getOrDefault(columnName, Collections.emptyList());
152    }
153
154    /**
155     * Get all exactly matched columns
156     */
157    public List<TObjectName> getExactMatches() {
158        return Collections.unmodifiableList(exactMatches);
159    }
160
161    /**
162     * Get all ambiguous columns
163     */
164    public List<TObjectName> getAmbiguousColumns() {
165        return Collections.unmodifiableList(ambiguousColumns);
166    }
167
168    /**
169     * Get all unresolved columns
170     */
171    public List<TObjectName> getUnresolvedColumns() {
172        return Collections.unmodifiableList(unresolvedColumns);
173    }
174
175    /**
176     * Get reference count for a specific table
177     */
178    public int getTableReferenceCount(TTable table) {
179        return tableReferenceCounts.getOrDefault(table, 0);
180    }
181
182    /**
183     * Get all tables that have been referenced
184     */
185    public Set<TTable> getAllReferencedTables() {
186        return tableReferences.keySet();
187    }
188
189    /**
190     * Get resolution statistics
191     */
192    public ResolutionStatistics getStatistics() {
193        return new ResolutionStatistics(
194            totalColumnReferences,
195            exactMatches.size(),
196            ambiguousColumns.size(),
197            unresolvedColumns.size(),
198            tableReferences.size()
199        );
200    }
201
202    /**
203     * Get resolution result for a specific TObjectName
204     */
205    public ResolutionResult getResolution(TObjectName objName) {
206        return resolutions.get(objName);
207    }
208
209    /**
210     * Clear all data (for reuse or testing)
211     */
212    public void clear() {
213        resolutions.clear();
214        tableReferences.clear();
215        columnNameIndex.clear();
216        exactMatches.clear();
217        ambiguousColumns.clear();
218        unresolvedColumns.clear();
219        tableReferenceCounts.clear();
220        totalColumnReferences = 0;
221    }
222}