/*
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

package flex2.tools;

//import flex2.compiler.as3.SignatureExtension;
import flex2.compiler.common.Configuration;
import flex2.compiler.common.CompilerConfiguration;
//import flex2.compiler.config.FileConfigurator;
import flex2.compiler.config.ConfigurationBuffer;
import flex2.compiler.config.ConfigurationException;
import flex2.compiler.config.ConfigurationInfo;
import flex2.compiler.config.ConfigurationValue;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.util.CompilerMessage;
//import flex2.compiler.util.ThreadLocalToolkit;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;

/**
 * Common base class for most tool specific configurations.
 */
public abstract class ToolsConfiguration extends Configuration
{
    public ToolsConfiguration()
    {
    }

    private VirtualFile licenseFile;

    public VirtualFile getLicenseFile()
    {
        return licenseFile;
    }

    private void processDeprecatedOptions(ConfigurationBuffer configurationBuffer)
    {
		for (Iterator i = configurationBuffer.getVarIterator(); i.hasNext(); )
		{
			String var = (String) i.next();
			ConfigurationInfo info = configurationBuffer.getInfo(var);
			if (info.isDeprecated() && configurationBuffer.getVar(var) != null)
			{
				CompilerMessage.CompilerWarning warning = info.getDeprecatedMessage();
				//String replacement = info.getDeprecatedReplacement();
				//String since = info.getDeprecatedSince();
				
				if (warning != null)
				{
					//ThreadLocalToolkit.log(warning);
				}
				else
				{
					//ThreadLocalToolkit.log(new DeprecatedConfigurationOption(var, replacement, since));
				}
			}
		}		
    }
    
    public static class DeprecatedConfigurationOption extends CompilerMessage.CompilerWarning
    {
    	private static final long serialVersionUID = 5523004100027677184L;

        public DeprecatedConfigurationOption(String var, String replacement, String since)
    	{
    		this.var = var;
    		this.replacement = replacement;
    		this.since = since;
    	}
    	
    	public final String var, replacement, since;
    }

	protected String output;

	public String getOutput()
    {
        return output;
    }

    abstract protected String getTargetFile();

    private String createOutputDirectory(ConfigurationBuffer configurationBuffer,
                                         String directory)
    {
        String result = directory;
        String parent =
            configurationBuffer.getToken(flex2.tools.oem.Configuration.DEFAULT_OUTPUT_DIRECTORY_TOKEN);
        
        if (parent == null)
        {
            String output = getOutput();

            if (output != null)
            {
                parent = (new File(output)).getParent();
            }
            else
            {
                // Fall back on the target file as a last resort.
                String targetFile = getTargetFile();

                if (targetFile != null)
                {
                    parent = (new File(targetFile)).getParent();
                }
            }
        }

        if (parent != null)
        {
            result = parent + File.separatorChar + directory;
        }

        return result;
    }

	public void validate(ConfigurationBuffer configurationBuffer) throws ConfigurationException
    {
		// process the merged configuration buffer. right, can't just process the args.
		processDeprecatedOptions(configurationBuffer);

		// For Apache Flex there is no license check.
		
		// If license.jar is present, call flex.license.OEMLicenseService.getLicenseFilename().
//		try
//		{
//			Class oemLicenseServiceClass = Class.forName("flex.license.OEMLicenseService");
//			Method method = oemLicenseServiceClass.getMethod("getLicenseFilename", (Class[])null);
//			String licenseFileName = (String)method.invoke(null, (Object[])null);
//			licenseFile = configResolver.resolve(licenseFileName);
//		}
//		catch (Exception e)
//		{
//		}
//
//        if (Trace.license)
//        {
//            final String file = (licenseFile != null) ? licenseFile.getName() : "";
//            Trace.trace("ToolsConfiguration.validate: licenseFile = '" + file + "'");
//        }
        
	    // validate the -AS3, -ES and -strict settings
	    boolean strict = "true".equalsIgnoreCase(configurationBuffer.peekSimpleConfigurationVar(CompilerConfiguration.STRICT));
	    boolean as3 = "true".equalsIgnoreCase(configurationBuffer.peekSimpleConfigurationVar(CompilerConfiguration.AS3));
	    boolean es = "true".equalsIgnoreCase(configurationBuffer.peekSimpleConfigurationVar(CompilerConfiguration.ES));

	    if ((as3 && es) || (!as3 && !es))
	    {
		    throw new BadAS3ESCombination(as3, es);
	    }
	    else if (strict && es)
	    {
		    //ThreadLocalToolkit.log(new BadESStrictCombination(es, strict));
	    }
        
        // if we're saving signatures to files and the directory is unset, use the default.
        final CompilerConfiguration compilerConfiguration = getCompilerConfiguration();

        validateKeepGeneratedSignatures(configurationBuffer, compilerConfiguration);
        validateKeepGeneratedActionScript(configurationBuffer, compilerConfiguration);
        validateDumpConfig(configurationBuffer);
    }

    private void validateDumpConfig(ConfigurationBuffer configurationBuffer)
        throws ConfigurationException
    {
        /*
        if (dumpConfigFile != null)
        {
            ThreadLocalToolkit.log(new Mxmlc.DumpConfig(dumpConfigFile));
            File f = new File(dumpConfigFile);
            // fixme - nuke the private string for the localization prefix...
            String text = FileConfigurator.formatBuffer(configurationBuffer, "royale-config",
                                                        ThreadLocalToolkit.getLocalizationManager(),
                                                        "flex2.configuration");
            try
            {
                PrintWriter out = new PrintWriter(new BufferedOutputStream(new FileOutputStream(f)));
                out.write(text);
                out.close();
            }
            catch (Exception e)
            {
                throw new ConfigurationException.IOError(dumpConfigFile);
            }
        }
        */
    }

    private void validateKeepGeneratedSignatures(ConfigurationBuffer configurationBuffer,
                                                 CompilerConfiguration compilerConfiguration)
        throws ConfigurationException
    {
        /*
        if (compilerConfiguration.getKeepGeneratedSignatures())
        {
            String dir = compilerConfiguration.getSignatureDirectory();

            if (dir == null)
            {
                dir = createOutputDirectory(configurationBuffer, SignatureExtension.DEFAULT_SIG_DIR);
            }
            else if (!FileUtils.isAbsolute(new File(dir)))
            {
                dir = createOutputDirectory(configurationBuffer, dir);
            }

            assert dir != null;

            if (dir != null)
            {
                File file = new File(dir);
                file.mkdirs();
                compilerConfiguration.setSignatureDirectory(FileUtils.canonicalPath(file));
            }
        }
        */
    }

    private void validateKeepGeneratedActionScript(ConfigurationBuffer configurationBuffer,
                                                 CompilerConfiguration compilerConfiguration)
    {
        if (compilerConfiguration.keepGeneratedActionScript())
        {
            String dir = compilerConfiguration.getGeneratedDirectory();

            if (dir == null)
            {
                dir = createOutputDirectory(configurationBuffer, "generated");
            }
            else if (!(new File(dir)).isAbsolute())
            {
                dir = createOutputDirectory(configurationBuffer, dir);
            }

            assert dir != null;

            if (dir != null)
            {
                File file = new File(dir);
                file.mkdirs();
                try {
                compilerConfiguration.setGeneratedDirectory(file.getCanonicalPath());
                } catch (IOException e)
                {
                }
            }
        }
    }

	public static class BadAS3ESCombination extends ConfigurationException
	{
	    private static final long serialVersionUID = 4418178171352281793L;

        public BadAS3ESCombination(boolean as3, boolean es)
	    {
	        super("");
		    this.as3 = as3;
		    this.es = es;
	    }

		public final boolean as3, es;
	}

	public static class BadESStrictCombination extends ConfigurationException
	{
	    private static final long serialVersionUID = 384624904213418743L;

        public BadESStrictCombination(boolean es, boolean strict)
	    {
	        super("");
		    this.es = es;
		    this.strict = strict;
	    }

		public final boolean es, strict;

		public String getLevel()
		{
		    return WARNING;
		}
	}
    
    //
    // 'warnings' option
    //
    
    private boolean warnings = true;
    
    public boolean getWarnings()
    {
        return warnings;
    }

    public void cfgWarnings(ConfigurationValue cv, boolean b)
    {
        warnings = b;
    }

    public static ConfigurationInfo getWarningsInfo()
    {
        return new ConfigurationInfo();
    }
    
    //
    // 'dump-config-file' option
    //

    private String dumpConfigFile = null;

    public String getDumpConfig()
    {
        return dumpConfigFile;
    }

    public void cfgDumpConfig(ConfigurationValue cv, String filename)
    {
        dumpConfigFile = Configuration.getOutputPath(cv, filename);
        // can't print here, we want to aggregate all the settings found and then print.
    }

    public static ConfigurationInfo getDumpConfigInfo()
    {
        return new ConfigurationInfo( 1, "filename" )
        {
            public boolean isAdvanced()
            {
                return true;
            }

            public boolean isDisplayed()
            {
                return false;
            }
        };
    }
}

