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

package com.togethersoft.modules.patterns.UNIVERSAL.CLASS.Stub_Implementation;

import java.util.Enumeration;

import com.togethersoft.openapi.sci.*;
import com.togethersoft.openapi.sci.enum.*;

import com.togethersoft.openapi.sci.pattern.SciPattern;
import com.togethersoft.openapi.sci.pattern.SciPatternUtil;

import com.togethersoft.openapi.ide.message.IdeMessageManagerAccess;
import com.togethersoft.openapi.ide.message.IdeMessageType;

import com.togethersoft.modules.patterns.UNIVERSAL.PatternBase;
import com.togethersoft.modules.patterns.UNIVERSAL.PatternBaseException;
import com.togethersoft.modules.patterns.UNIVERSAL.PatternUIBuilder;

/**
 * Stub implementation pattern
 * @author TogetherSoft
 */
public class Pattern extends PatternBase implements SciPattern {

    private static final String PATTERN_NAME = "Stub Implementation";

    public Pattern() {
        setPatternDisplayName(PATTERN_NAME);
    }

    protected void finalize() throws Throwable {
        super.finalize();
        myUIBuilder = null;
    }

    public boolean prepare() {
        super.prepare();
        try {
            SciElement testElement = getElement();
            if (testElement == null || !(testElement instanceof SciClass)) {
                throw new PatternBaseException("This pattern should be applied to existing class");
            }

            cannotApplyToInterface((SciClass)testElement);

            setPropertyValue(EXPORT_DOCUMENTATION, Boolean.FALSE);

            initializeInspector();
            return true;
        }
        catch (PatternBaseException e) {
            return false;
        }
    }

    public boolean canApply() {
        return true;
    }

    public void apply() {
        if (!canApply()) {
            return;
        }
        super.apply();

        SciClass aClass = (SciClass) getElement();

        SciClass baseClass = null;
        SciInheritanceEnumeration extendsEnum = aClass.getExtendsList().inheritances();
        if (extendsEnum.hasMoreElements()) {
            baseClass = (SciClass) extendsEnum.nextSciInheritance().getReferencedElement();
        }

        // Stub operations
        Enumeration members = SciUtil.allMembers(aClass, true);
        while (members.hasMoreElements()) {
            Object member = members.nextElement();
            if (!(member instanceof SciOperation)) {
                continue;
            }

            SciOperation anOperation = (SciOperation) member;
            if (!anOperation.hasProperty(SciProperty.ABSTRACT)) {
                continue;
            }

            if (SciUtil.findMemberBySignature(aClass, anOperation) != null) {
                continue;
            }

            //System.out.println("operation = " + anOperation.getName());
            anOperation = (SciOperation) aClass.paste(anOperation, null, false);
            anOperation.setProperty(SciProperty.ABSTRACT, false);

            if (!exportDocumentation()) {
                SciTagEnumeration tags = anOperation.getTagList().tags();
                while (tags.hasMoreElements()) {
                    tags.nextSciTag().setValue(null);
                }
            }

            SciPatternUtil.makeStubImplementation(anOperation);
        }

        if (baseClass != null) {
            // Stub ctors/dtors
            SciOperationEnumeration operations = baseClass.operations();
            while (operations.hasMoreElements()) {
                SciOperation anOperation = (SciOperation) operations.nextElement();
                //System.out.println("operation = " + anOperation.getName());

                if (SciUtil.findMemberBySignature(aClass, anOperation) != null) {
                    continue;
                }

                if (!anOperation.hasProperty(SciProperty.CONSTRUCTOR) &&
                    !anOperation.hasProperty(SciProperty.DESTRUCTOR)) {
                    continue;
                }

                if (anOperation.hasProperty(SciProperty.PRIVATE) ||
                    anOperation.hasProperty(SciProperty.PROTECTED)) {
                    continue;
                }

                anOperation = (SciOperation) aClass.paste(anOperation, null, false);
                anOperation.setProperty(SciProperty.ABSTRACT, false);

                if (!exportDocumentation()) {
                    SciTagEnumeration tags = anOperation.getTagList().tags();
                    while (tags.hasMoreElements()) {
                        tags.nextSciTag().setValue(null);
                    }
                }

                try {
                    String params = EMPTY_STRING;
                    SciParameterEnumeration parameters = anOperation.getParameterList().parameters();
                    while (parameters.hasMoreElements()) {
                        params += parameters.nextSciParameter().getName();
                        if (parameters.hasMoreElements()) {
                            params += ", ";
                        }
                    }

                    String code = EMPTY_STRING;
                    if (SciLanguage.JAVA.equals(getLanguage())) {
                        code = "\nsuper(" + params + ");\n";
                    }
                    anOperation.setBody(getGenericFactory().newCodeBlock(code));
                }
                catch (SciGenericFactoryException e) {
                    IdeMessageManagerAccess.printMessage(IdeMessageType.ERROR, CODE_GENERATION_ERROR);
                }
            }
        }

        myUIBuilder = null;
    }

    protected void initializeInspector() {
        try {
            myUIBuilder = null;
            myUIBuilder = createUIBuilder(true);

            // Create page
            String pageName1 = "Pattern properties";
            if (myUIBuilder.addInspectorPage(pageName1, PatternUIBuilder.UIPresentation.Table) == null) {
                throw new PatternBaseException(CANNOT_CREATE_PATTERN_UI);
            }

            if (myUIBuilder.AddExportDocumentationProperty(pageName1) == null) {
                throw new PatternBaseException(CANNOT_CREATE_PATTERN_UI);
            }

            myUIBuilder.setCreatedPatternUI();
        }
        catch (PatternBaseException ex) {
            myUIBuilder = null;
            getIdeInspector().clear();
            return;
        }
    }

    private PatternUIBuilder myUIBuilder = null;
}
