/*
 * Created on 2004-12-22
 *
 * Part of the Symbian development plug-in for Eclipse
 * Copyright (C) Mikołaj Zalewski, 2004
 */
package pl.zalewski.mikolaj.symbdev.core.internal.mmpparser;

import java.util.Iterator;
import java.util.LinkedList;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;

import pl.zalewski.mikolaj.symbdev.SymbdevPlugin;
import pl.zalewski.mikolaj.symbdev.core.internal.mmpmodel.AIFDeclaration;
import pl.zalewski.mikolaj.symbdev.core.internal.mmpmodel.MMPModel;
import pl.zalewski.mikolaj.symbdev.core.mmpmodel.MMPCommands;
import pl.zalewski.mikolaj.symbdev.core.mmpmodel.MMPFileReference;

/**
 * Parser of the main commands - outside START SOMETHING ... END
 * 
 * @author mikolaj
 */
public class MainCommandParser extends AbstractCommandParser {

    static final public String[] fKeywords=new String[]{
            "TARGET",
            "TARGETTYPE",
            "UID",
            "TARGETPATH",
            "LANG",
            MMPCommands.OPTION,
            MMPCommands.MACRO,
            "EPOCHEAPSIZE",
            "EPOCSTACKSIZE",
            "EPOCPROCESSPRIORITY",
            "LINKAS",
            "NOSTRICTDEF",
            "SRCDBG",
            "STRICTDEPEND",
            MMPCommands.RESOURCE,
            MMPCommands.SYSTEMRESOURCE,
            MMPCommands.SOURCE,
            // source path must be declared after all the commands that depends
            // on on this path (for MMPParser.findSourceBestPlace to work)
            MMPCommands.SOURCEPATH,
            
            MMPCommands.USERINCLUDE,
            MMPCommands.SYSTEMINCLUDE,
            "START",
            "LIBRARY",
            "DEBUGLIBRARY",
            MMPCommands.AIF,
            // these commands are ignored by the model, however they
            // are not underlined as errors
            MMPCommands.EXPORTUNFROZEN,
            MMPCommands.DEFFILE,
            MMPCommands.STATICLIBRARY,
            MMPCommands.WIN32_LIBRARY
    };
    
    static final public String[] fOptionsCompilers=new String[]{
            "MSVC",
            "CW",
            "GCC"
    };
    
    static final public String[] fPriorities=new String[]{
            "LOW",
            "BACKGROUND",
            "FOREGROUND",
            "HIGH",
            "WINDOWSERVER",
            "FILESERVER",
            "REALTIMESERVER",
            "SUPERVISOR"
    };

    
    public MainCommandParser(MMPModel model, MMPParser parser) {
        super(model, parser);
        fSourcePath=fParser.getGroupDir();
    }
    
    static public boolean doesDependOnSourcePath(String command)
    {
        if (MMPCommands.RESOURCE.equalsIgnoreCase(command) ||
                MMPCommands.SYSTEMRESOURCE.equalsIgnoreCase(command) ||
                MMPCommands.SOURCE.equalsIgnoreCase(command) ||
                MMPCommands.DOCUMENT.equalsIgnoreCase(command))
            return true;
        return false;
    }

    protected LinkedList parse(String cmd, Iterator it, AbstractTokenParser cmdToken) {
        LinkedList ret=new LinkedList();
        try {
	        String cmdi=cmd.toUpperCase().intern();
	        if (cmdi=="TARGET")
	        {
	            StringTokenParser t=new StringTokenParser(it);
	            t.parseAndAddTo(ret);
	            fModel.setTargetFilename(t.fContent);
	        } else if (cmdi=="TARGETPATH")
	        {
	            StringTokenParser t=new StringTokenParser(it);
	            t.parseAndAddTo(ret);
	            fModel.setTargetPath(t.fContent);
	        } else if (cmdi=="TARGETTYPE")
	        {
	            StringTokenParser t=new StringTokenParser(it);
	            t.parseAndAddTo(ret);
	            fModel.setTargetType(t.fContent);
	        } else if (cmdi=="LANG")
	        {
	            StringTokenParser t;
	            while (it.hasNext())
	            {
	                t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addLanguages(new String[]{t.fContent});
	            }
	        } else if (cmdi=="UID")
	        {
	            NumberTokenParser t;
	            while (it.hasNext())
	            {
	                t=new NumberTokenParser(it);
	                t.parseAndAddTo(ret);
	                if (fLoadedUIDs<2)
	                {
	                    if (fLoadedUIDs==0) fModel.setUID2(t.fValue);
	                		else fModel.setUID3(t.fValue);
	                } else t.setError(IMarker.SEVERITY_ERROR, "Two UIDs already declared");
	                fLoadedUIDs++;
	            }            
	        } else if (cmdi==MMPCommands.SOURCEPATH)
	        {
	            PathTokenParser t=new PathTokenParser(it,
	                    fParser.getSDKRoot(),
	                    fParser.getGroupDir());
	            t.parseAndAddTo(ret);
	            fSourcePath=t.fPath;
	            fSourceString=t.fContent;
	            fParser.setExtraInfo(t.fContent);
	        } else if (cmdi==MMPCommands.OPTION)
	        {
	            FiniteChoiceTokenParser t=new FiniteChoiceTokenParser(it, fOptionsCompilers);
	            String options=null;
	            while (it.hasNext())
	            {
	                StringTokenParser opt=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                if (options==null) options=opt.fContent;
	                	else options=options+" "+opt.fContent;
	            }
	            t.parseAndAddTo(ret);
	            fModel.addCompilerOptions(t.fContent, options);
	        } else if (cmdi==MMPCommands.MACRO)
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
                	t.parseAndAddTo(ret);
	            	fModel.addMacro(t.fContent);
	            }
	        } else if (cmdi=="EPOCHEAPSIZE")
	        {
	            NumberTokenParser min=new NumberTokenParser(it);
	            min.parseAndAddTo(ret);
	            NumberTokenParser max=new NumberTokenParser(it);
	            max.parseAndAddTo(ret);
	            fModel.setHeapMin(min.fValue);
	            fModel.setHeapMax(max.fValue);
	        } else if (cmdi=="EPOCSTACKSIZE")
	        {
	            NumberTokenParser t=new NumberTokenParser(it);
	            t.parseAndAddTo(ret);
	            fModel.setStackSize(t.fValue);
	        } else if (cmdi=="EPOCPROCESSPRIORITY")
	        {
	            FiniteChoiceTokenParser t=new FiniteChoiceTokenParser(it, fPriorities);
	            t.parseAndAddTo(ret);
	            fModel.setPriority(t.fContent);
	        } else if (cmdi=="NOSTRICTDEF")
	        {
	            fModel.setNoStrictDef(true);
	        } else if (cmdi=="SRCDBG")
	        {
	            fModel.setSrcDbg(true);
	        } else if (cmdi=="STRICTDEPEND")
	        {
	            fModel.setStrictDepend(true);
	        } else if (cmdi=="LINKAS")
	        {
                StringTokenParser t=new StringTokenParser(it);
            	t.parseAndAddTo(ret);
	            fModel.setLinkAs(t.fContent);
	        } else if (cmdi=="START")
	        {
	            StringTokenParser t=new StringTokenParser(it);
	            // TODO
	            t.parseAndAddTo(ret);
	            fParser.startEnvironment(new UnknownCommandParser(fModel, fParser, t.fContent));
	            while (it.hasNext())
	                it.next();
	        } else if (cmdi=="LIBRARY")
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addLibrary(t.fContent);
	            }
	        } else if (cmdi=="DEBUGLIBRARY")
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addDebugLibrary(t.fContent);
	            }	            
	        } else if (cmdi==MMPCommands.USERINCLUDE)
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addUserInclude(t.fContent);
	            }	            
	        } else if (cmdi==MMPCommands.SYSTEMINCLUDE)
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addSystemInclude(t.fContent);
	            }	            
	        } else if (cmdi==MMPCommands.RESOURCE)
	        {
	            while (it.hasNext())
	            {
	                // TODO PathTokenParser
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addResource(new MMPFileReference(t.fContent, fSourceString));
	            }	            
	        } else if (cmdi==MMPCommands.SYSTEMRESOURCE)
	        {
	            while (it.hasNext())
	            {
	                // TODO PathTokenParser
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addSystemResource(new MMPFileReference(t.fContent, fSourceString));
	            }
	        } else if (cmdi==MMPCommands.AIF) {
	            if (fModel.getAIFDeclaration()!=null)
	            {
	                cmdToken.setError(IMarker.SEVERITY_ERROR, "An AIF is already defined");
	            } else {
		            StringTokenParser target=new StringTokenParser(it);
		            target.parseAndAddTo(ret);
		            // TODO PathTokenParsers
		            StringTokenParser sourcePath=new StringTokenParser(it);
		            sourcePath.parseAndAddTo(ret);
		            StringTokenParser sourceFile=new StringTokenParser(it);
		            sourceFile.parseAndAddTo(ret);
		            fModel.createAIFDeclaration(new MMPFileReference(sourceFile.fContent,
		                    sourcePath.fContent), target.fContent);
		            // we need to add bitmaps directly
		            AIFDeclaration aif=(AIFDeclaration)fModel.getAIFDeclaration();
		            if (it.hasNext())
		            {
		                StringTokenParser depth=new StringTokenParser(it);
		                String[] depths=depth.fContent.split(",");
		                int pos=0;
		                while (it.hasNext())
		                {
		                    StringTokenParser bitmap=new StringTokenParser(it);
	                        aif.addBitmap(
	                                new MMPFileReference(bitmap.fContent, sourcePath.fContent),
	                                	depths[pos%depths.length]);
	                        pos++;
		                }
		            }
	            }
	        } else if (cmdi=="SOURCE") {
	            while (it.hasNext()) {
	                // TODO PathTokenParser
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	                fModel.addSourceMMPItem(new MMPFileReference(t.fContent, fSourceString));
	            }	            
	        } else  // ignore other commands
	        {
	            while (it.hasNext())
	            {
	                StringTokenParser t=new StringTokenParser(it);
	                t.parseAndAddTo(ret);
	            }
	        }
        }
        catch (CoreException e)
        {
            SymbdevPlugin.log(e);
        }
        return ret;
    }

    public String[] getKeywords() {
        return fKeywords;
    }
    
    /**
     * Returns the id (the position in the keyworkd tables of this
     * keyword). When adding a statement the parser will try to add
     * the keywords in order of increasing ids 
     * @param cmd The keyword
     * @return The id (0..fKeywords.length()-1 if keyword known or
     * fKeywords.length() if unknown)
     */
    public static int getKeywordId(String cmd)
    {
        int i;
        for (i=0; i<fKeywords.length; i++)
            if (fKeywords[i].equalsIgnoreCase(cmd))
                break;
        return i;
    }

    public void commandsEnd()
    {
    }

    IPath fSourcePath;
    String fSourceString;
    int fLoadedUIDs=0;
}
