package de.uni_hildesheim.sse.trans.in;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FilenameUtils;

import de.uni_hildesheim.sse.model.validation.IvmlIdentifierCheck;
import de.uni_hildesheim.sse.model.varModel.DecisionVariableDeclaration;
import de.uni_hildesheim.sse.model.varModel.Project;
import de.uni_hildesheim.sse.model.varModel.datatypes.BooleanType;
import de.uni_hildesheim.sse.model.varModel.datatypes.IDatatype;

/**
 * Abstract super class for {@link IModelReader}.
 * @author El-Sharkawy
 *
 */
public abstract class AbstractReader implements IModelReader {
    private Project model;
    private BufferedReader reader;
    private Map<String, DecisionVariableDeclaration> variables;
    
    /**
     * Sole constructor for this abstract reader.
     * @param inputFile The file to be read.
     * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file,
     * or for some other reason cannot be opened for reading.
     */
    protected AbstractReader(File inputFile) throws FileNotFoundException {
        reader = new BufferedReader(new FileReader(inputFile));
        
        String name = FilenameUtils.removeExtension(inputFile.getName());
        while (!IvmlIdentifierCheck.isValidIdentifier(name)) {
            // Replace whitespaces
            name = name.replaceAll("\\s", "_");
            // Replace "punctuation" signs, like !, #, <, ...
            name = name.replaceAll("\\p{Punct}", "_");
            // If name starts with a number, add _ at the beginning
            if (Character.isDigit(name.charAt(0))) {
                name = "_" + name;
            }
        }
        
        model = new Project(name);
        variables = new HashMap<String, DecisionVariableDeclaration>();
    }

    /**
     * Returns the model of the current translation.
     * @return The model, which is still used inside the current translation.
     */
    protected final Project getModel() {
        return model;
    }
    
    /**
     * Returns a {@link DecisionVariableDeclaration} for the specified name. If such a variables was not created yet,
     * a new variable will be created and added to the {@link #model}.
     * @param name The name of the desired variable.
     * @return A boolean {@link DecisionVariableDeclaration} with the specified name.
     */
    public final DecisionVariableDeclaration getVariable(String name) {
        return getVariable(name, BooleanType.TYPE);
    }
    /**
     * Returns a {@link DecisionVariableDeclaration} for the specified name. If such a variables was not created yet,
     * a new variable will be created and added to the {@link #model}.
     * @param name The name of the desired variable.
     * @param type The {@link IDatatype} of the {@link DecisionVariableDeclaration}, will be used for creating the
     *     variable if it does not exist.
     * @return A boolean {@link DecisionVariableDeclaration} with the specified name.
     */
    protected final DecisionVariableDeclaration getVariable(String name, IDatatype type) {
        DecisionVariableDeclaration variable = variables.get(name);
        if (null == variable) {
            variable = new DecisionVariableDeclaration(name, type, model);
            model.add(variable);
            variables.put(name, variable);
        }
        
        return variable;
    }
    
    /**
     * Returns the {@link BufferedReader} of the given <tt>inputFile</tt>.
     * @return The {@link BufferedReader} of the given <tt>inputFile</tt>
     */
    protected final BufferedReader getReader() {
        return reader;
    }
}
