/*----------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft Corporation. Patents pending. All rights reserved.
----------------------------------------------------------------------------*/

package com.togethersoft.modules.qa.utils;

import java.awt.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import com.togethersoft.openapi.ide.*;
import com.togethersoft.openapi.ide.window.*;
import com.togethersoft.openapi.sci.*;
import com.togethersoft.openapi.sci.enum.*;
import com.togethersoft.modules.qa.*;
import com.togethersoft.modules.qa.api.*;


/**
 * Metroics plugin implementation -
 * abstract class serving as ancestor for all metrics plugins
 * @version 3.1.0
 * @author TogetherSoft
 *
 **/
public abstract class MetricsPluginImpl extends PluginImpl implements MetricsPlugin
{

    /**
     * Does nothing but set current scope
     * in accordance with getMinimalScope() and getMaximalScope()
     */
    protected MetricsPluginImpl() {
		// setCurrentScope would verify whether parameter
        // comply min-max range
        setCurrentScope(SCOPE_CLASS);
    }

    /**
     * Plugin entry point.
     * It is invoked for every package and every class selected in diagram as well as for each their subpackage and subclass.
     * @param obj Source Code Interface object to process
     * @param result object to store processing results
     * If returns <code>false</code>, further processing is stopped.
     * @return <code>true</code> to proceed further objects, otherwise <code>false</code>
     **/
	public boolean run (String abbr, SciObject obj, MetricsResult result) {
        MetricsPluginHolder hldr = Metrics.holders.getByAbbreviation(abbr);
        if (hldr == null)
            return false;

        result.setValue(0);
        result.setVoid(true);
        return hldr.run(obj, result);
    }


    /**
     * Gets the <i>minimal</i> scope on which plugin results may be applicable.
     * It may be <code>SCOPE_PROJECT</code>, <code>SCOPE_CLASS</code>,
     * <code>SCOPE_PACKAGE</code> or <code>SCOPE_OPERATION</code>.
	 *
	 * @return
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
     *
     * @deprecated Since 4.2 use <code>getMinimalScope</code> instead
	 **/
	public int getScope() {
        return SCOPE_CLASS;
    }

    /**
     * Gets the <i>minimal</i> scope on which plugin results may be applicable.
     * It may be <code>SCOPE_PROJECT</code>, <code>SCOPE_CLASS</code>,
     * <code>SCOPE_PACKAGE</code> or <code>SCOPE_OPERATION</code>.
	 *
	 * @return
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
	 **/
    public int getMinimalScope() {
        // normally it should return SCOPE_CLASS by default -
        // but earlier analogous method was named 'getScope' -
        // therefore for the sake of compatibility we call getScope
        // and getScope default implementation returns SCOPE_CLASS
        return getScope();
    }

    /**
     * Gets the <i>maximal</i> scope on which plugin results may be applicable.
     * It may be <code>SCOPE_PROJECT</code>, <code>SCOPE_CLASS</code>,
     * <code>SCOPE_PACKAGE</code> or <code>SCOPE_OPERATION</code>.
	 *
	 * @return on of
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
	 **/
    public int getMaximalScope() {
        return Math.max(SCOPE_CLASS, getMinimalScope());
    }

    protected int scope = SCOPE_CLASS;

    /**
     * Determines whether the current plugin scope is operation, class, package or project scope.
     * @return one of
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
     */
    public int getCurrentScope() {
        return scope;
    }

    /**
     * Sets plugin scope - operation, class, package or project scope.
     * @param scope sets plugin
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
     */
    public void setCurrentScope(int scope) {
        int minScope = getMinimalScope();
        int maxScope = getMaximalScope();
        /*
        if( scope < minScope || scope > maxScope ) {
            throw new IllegalArgumentException("attempt to set plugin scope " + scope
                							+ " which doesn't lay in interval " + minScope + "-" + maxScope);
        }
        */
        if( scope < minScope )
            this.scope = minScope;
        else if( scope > maxScope )
            this.scope = maxScope;
        else
        	this.scope = scope;
    }


    /**
     * Returns numeric value of scope of the given SciObject ()
     * @param SciObject object whose scope would be return
	 * @return on of
     * <code>SCOPE_OPERATION</code> if plugin results may be applied to the individual operations,
     * <code>SCOPE_CLASS</code> if plugin results may be applied to the classes,
     * <code>SCOPE_PACKAGE</code> if plugin results may be applied to the packages,
     * <code>SCOPE_PROJECT</code> if they can be applied to the whole project only.
     */
    public static int getObjectScope(SciObject obj) {
        if( obj instanceof SciOperation ) {
            return SCOPE_OPERATION;
        }
        else if( obj instanceof SciClass ) {
            return SCOPE_CLASS;
        }
        else if( obj instanceof SciPackage ) {
            if( ChosenNodes.isRootPkg((SciPackage) obj) && ChosenNodes.getProjectRoots().length == 1 ) {
                return SCOPE_PROJECT;
            }
            else {
                return SCOPE_PACKAGE;
            }
    	}
        else {
            return SCOPE_UNDEFINED;
        }
    }

    /**
	 * Gets default lower limit value
	 *
     * @return default lower limit value
	 *
	 * @deprecated Since Together 4.01 this method is never called.
	 * Defaults are now provided by loading default value sets from files.
	 **/
	public int getDefaultLowerLimit () {
        return 0;
    }

    /**
	 * Gets default upper limit value
	 *
     * @return default upper limit value
	 *
	 * @deprecated Since Together 4.01 this method is never called.
	 * Defaults are now provided by loading default value sets from files.
	 **/
	public int getDefaultUpperLimit () {
        return 0;
    }


    /**
     * Gets default aggregation for plugin.
     * May be on of
     * <code>AGGR_NONE</code>,
     * <code>AGGR_SUM</code>,
     * <code>AGGR_AVERAGE</code>,
     * <code>AGGR_MINIMUM</code>,
     * <code>AGGR_MAXIMUM</code> or
	 * <code>AGGR_MEDIAN</code>
	 *
	 * @return default aggregation
	 *
	 * @deprecated Since Together 4.01 this method is never called.
	 * Defaults are now provided by loading default value sets from files.
	 **/
	public String getDefaultAggregation() {
        return AGGR_NONE;
	}

	/**
	 * lower limit value
	 * @see #getLowerLimit()
	 * @see #setLowerLimit()
	 */
	private int lowerLimit;

	public int getLowerLimit() {
		return lowerLimit;
	}

	public void setLowerLimit(int lowerLimit) {
		this.lowerLimit = lowerLimit;
	}

	/**
	 * upper limit value
	 * @see #getUpperLimit()
	 * @see #setUpperLimit()
	 */
	private int upperLimit;

	public int getUpperLimit() {
		return upperLimit;
	}

	public void setUpperLimit(int upperLimit) {
		this.upperLimit = upperLimit;
	}

	/**
	 * aggregation
	 * @see #getAggregation()
	 * @see #setAggregation()
	 */
	private String aggregation;

	public String getAggregation() {
		return aggregation;
	}

	public void setAggregation(String aggregation) {
		this.aggregation = aggregation;
	}

    /*
	public boolean hasPackageResults() {
		return false;
	}
    */

    /**
     * Gets the of description file name of plugin
     * By default, description file name is the same as plugin class file name but with the extemsion of ".html".
     * @return description file name
     **/
	public String getDescriptionFileName() {
        String name = Utils.getClsName(this);
        String fileName = TgUtils.getMetricsHomeDir() +
            File.separator + name +
            File.separator + name + ".html";
        return fileName;
    }


	/**
	 * plugin's property name prefix
	 */
	private String propertyPrefix = null;

	protected String getPropertyPrefix() {
		if( propertyPrefix == null ) {
			String s = getClass().getName();
			int pos = s.lastIndexOf('.');
			propertyPrefix = "Metrics." + s.substring(pos + 1);
		}
		return propertyPrefix;
	}

	protected Properties getProperties() {
		return Metrics.getProperties();
	}

	// used to restore options from  the properties file.
	public void restoreOptions() {
		setLowerLimit(getProperty("LowerLimit", 0));
		setUpperLimit(getProperty("UpperLimit", 0));
		setAggregation(getProperty("Aggregation", AGGR_NONE));
        setCurrentScope(getProperty("Scope", getCurrentScope()));
		super.restoreOptions();
	}

	// used to store options from  the properties file.
	public boolean storeOptions() {
		putProperty("LowerLimit", getLowerLimit());
		putProperty("UpperLimit", getUpperLimit());
		putProperty("Aggregation", getAggregation());
        putProperty("Scope", getCurrentScope());
		return super.storeOptions();
	}
}
