package metalexer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;

import metalexer.ast.Component;
import metalexer.ast.ComponentWrapper;
import metalexer.ast.Layout;
import metalexer.ast.LayoutWrapper;
import beaver.Parser;
import beaver.Symbol;

public class FileLoaderHelper {
    private final String baseDir;
    
    private final Map<String, Component> components;
    private final Map<String, Layout> layouts;

    public FileLoaderHelper(String baseDir) {
        this.baseDir = baseDir;
        this.components = new HashMap<String, Component>();
        this.layouts = new HashMap<String, Layout>();
    }

    public Component loadComponent(String compName, /*out*/ SortedSet<CompilationProblem> errors) throws IOException {
        if(components.containsKey(compName)) {
            //NB: won't re-add errors
            return components.get(compName);
        }
        String filename = baseDir + File.separator + expandQualifiedName(compName) + Constants.COMPONENT_FILE_EXT;
        BufferedReader in = openFile(filename);
        ComponentScanner scanner = new ComponentScanner(in);
        ComponentParser parser = new ComponentParser();
        parser.setFilename(filename);
        Component root = null;
        try {
            root = ((ComponentWrapper) parser.parse(scanner)).getComponent();
        } catch(Parser.Exception e) {
            //don't need to handle this - we automatically add them all to the outgoing list anyway
        }
        errors.addAll(parser.getProblems());
        components.put(compName, root);
        if(root != null && !root.getName().equals(compName)) {
            int pos = root.Namestart;
            int line = Symbol.getLine(pos);
            int col = Symbol.getColumn(pos);
            errors.add(new CompilationError(filename, line, col, "File name (" + compName + Constants.COMPONENT_FILE_EXT + ") does not match component name (" + root.getName() + ")."));
        }
        return root;
    }

    public Layout loadLayout(String layoutName, /*out*/ SortedSet<CompilationProblem> errors) throws IOException {
        if(layouts.containsKey(layoutName)) {
            //NB: won't re-add errors
            return layouts.get(layoutName);
        }
        String filename = baseDir + File.separator + expandQualifiedName(layoutName) + Constants.LAYOUT_FILE_EXT;
        BufferedReader in = openFile(filename);
        LayoutScanner scanner = new LayoutScanner(in);
        LayoutParser parser = new LayoutParser();
        parser.setFilename(filename);
        Layout root = null;
        try {
            root = ((LayoutWrapper) parser.parse(scanner)).getLayout();
        } catch(Parser.Exception e) {
            //don't need to handle this - we automatically add them all to the outgoing list anyway
        }
        errors.addAll(parser.getProblems());
        layouts.put(layoutName, root);
        if(root != null && !root.getName().equals(layoutName)) {
            int pos = root.Namestart;
            int line = Symbol.getLine(pos);
            int col = Symbol.getColumn(pos);
            errors.add(new CompilationError(filename, line, col, "File name (" + layoutName + Constants.LAYOUT_FILE_EXT + ") does not match layout name (" + root.getName() + ")."));
        }
        return root;

    }

    private static BufferedReader openFile(String fileName) throws IOException {
        return new BufferedReader(new FileReader(fileName));
    }
    
    private static String expandQualifiedName(String qualifiedName) {
        return qualifiedName.replaceAll("\\.", File.separator);
    }
}
