/*----------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft Corporation. Patents pending. All rights reserved.
----------------------------------------------------------------------------*/
package com.togethersoft.modules.patterns.JAVA.CLASS.HP_E_Speak.Service_Provider.code;

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

import com.togethersoft.openapi.util.propertyMap.PropertyMap;
import com.togethersoft.openapi.util.propertyMap.Property;

import com.togethersoft.modules.patterns.JAVA.CLASS.HP_E_Speak.Service_Provider.CompositeSciTemplate;
import com.togethersoft.modules.patterns.JAVA.CLASS.HP_E_Speak.Service_Provider.ClientProperty;
import com.togethersoft.modules.patterns.JAVA.CLASS.HP_E_Speak.Service_Provider.ClientConstant;

import  java.util.Enumeration;

class ServiceRegisterOpTemplate extends CompositeSciTemplate {

        /*
         * Defaults.
         */
        private static final String DEFAULT_SERVICE_NAME       = "net.espeak.jesi.ESService";
//        private static final String DEFAULT_SERVICE_NAME_SHORT = "ESService";

        public ServiceRegisterOpTemplate(PropertyMap properties) {
                super(properties);
                }

        public boolean prepare( SciObject target) {

                /*
                 * Provide initial value of ESService interface name.
                 */
                if (!exists(DEFAULT_SERVICE_NAME)) {
                        setErrorMessage("Interface " + DEFAULT_SERVICE_NAME + " was not found," +
                                        " add eslib.jar library to the classpath or as the project import root." );
                        return false;
                        }

                String esServiceName = DEFAULT_SERVICE_NAME;
                SciPackage parentPackage = null;

                if (target instanceof SciClass) {
                        // check target.
                        parentPackage = ((SciClass) target).getContainingPackage();
                        if (isESServiceInterface((SciClass) target)) {
                                esServiceName = ((SciElement) target).getQualifiedName();
                                }
                        }
                else if (target instanceof SciPackage) {
                        // check current package.
                        parentPackage = (SciPackage) target;
                        for(SciClassEnumeration classes = ((SciPackage) target).classes(); classes.hasMoreElements();) {
                                SciClass clazz = classes.nextSciClass();

                                if (isESServiceInterface(clazz)) {
                                        esServiceName = clazz.getQualifiedName();
                                        break;
                                        }
                                }
                        }


                setPropertyValue(ClientProperty.SERVICE_INTERFACE_NAME, esServiceName);
                return super.prepare(target);
                }

        public SciObject generate(SciObject target) {

                SciClass clazz = (SciClass) target;

                /*
                 * Add import statement for Service interface.
                 */
                if (!DEFAULT_SERVICE_NAME.equals(getPropertyValue(ClientProperty.SERVICE_INTERFACE_NAME))) {
                        // DEFAULT_SERVICE_NAME already imported.
                        SciJavaImport javaImport = getSciFactory().newJavaImport();
                        javaImport.setImportText(getStringPropertyValue(ClientProperty.SERVICE_INTERFACE_NAME));
                        clazz.getContainingFile().getJavaImportList().paste(javaImport, null, true);
                        }

                /*
                 * Generate operation.
                 */
                SciOperation operation = getSciFactory().newOperation();
                operation.setName("registerService");
                operation = (SciOperation) clazz.paste(operation, null, true);

                /*
                 * Generate registration code.
                 */
                String name = "\"" + getStringPropertyValue(ClientProperty.NAME_CONSTRAINT) + "\"";
                if (Boolean.TRUE.equals(getPropertyValue(ClientProperty.PARAMETRIZE_NAME_CONSTRAINT))) {
                        name = "this." + ServiceAttribute.GLOBAL_SERVICE_NAME;
                        }

                String code = "try {\n";
                if (ClientConstant.NAME_DESCRIPTION.equals(getPropertyValue(ClientProperty.SERVICE_DESCRIPTION_TYPE))) {
                        code += "ESServiceElement serviceElement = new ESServiceElement(getESConnection(), " + name + ");\n";
                        }
                else if (ClientConstant.CUSTOM_DESCRIPTION.equals(getPropertyValue(ClientProperty.SERVICE_DESCRIPTION_TYPE))) {
                        code += "ESVocabularyDescription vocabularyDescription = new ESVocabularyDescription();\n";
                        code += "vocabularyDescription.addAttribute(\"Name\", \"" + getPropertyValue(ClientProperty.VOCABULARY_NAME)+ "\");\n";
                        // custom properties names here.
                        for(Enumeration properties = getProperties().properties(ClientProperty.CUSTOM_CONSTRAINT); properties.hasMoreElements();) {
                                String propertyName = (String) ((Property) properties.nextElement()).getValue();
                                code += "vocabularyDescription.addStringProperty(\"" + propertyName + "\");\n";
                                }

                        code += "ESVocabularyElement vocabularyElement = new ESVocabularyElement(getESConnection(), vocabularyDescription);\n";
                        code += "ESVocabulary   vocabulary = vocabularyElement.register();\n";
                        code += "System.out.println(\"[HP-ES Service Provider] Vocabulary registered in HP-ES Core.\");\n";

                        code += "ESServiceDescription serviceDescription = new ESServiceDescription(vocabulary);\n";
                        // custom properties values here.
                        for(Enumeration properties = getProperties().properties(ClientProperty.CUSTOM_CONSTRAINT); properties.hasMoreElements();) {
                                String propertyName = (String) ((Property) properties.nextElement()).getValue();
                                String value = getStringPropertyValue("$$" + propertyName);
                                code += "serviceDescription.addAttribute(\"" + propertyName + "\", \"" + value + "\");\n";
                                }

                        code += "ESServiceElement serviceElement = new ESServiceElement(getESConnection(), serviceDescription);\n";
                        }

                code += "serviceElement.setImplementation(this." + ServiceAttribute.IMPLEMENTATION + ")\n;";
                code += "serviceElement.register();\n";
                code += "System.out.println(\"[HP-ES Service Provider] Service registered in HP-ES Core.\");\n";
                code += "serviceElement.start();\n";

                code += "System.out.println(\"[HP-ES Service Provider] Service started.\");\n";
                code += "\n}\ncatch(ESLibException libException) {\n";
                code += "handleException(\"during registering service\", libException);\n";
                code += "\n}\ncatch(ESInvocationException invocationException) {\n";
                code += "handleException(\"during registering service\", invocationException);\n";
                code += "\n}\ncatch(NameCollisionException nameCollisionException) {\n";
                code += "handleException(\"during registering service\", nameCollisionException);\n";
                code += "\n}";

                try {
                        SciCodeBlock codeBlock = getSciGenericFactory().newCodeBlock(code);
                        operation.setBody(codeBlock);
                        }
                catch(SciGenericFactoryException sciException) {
                        System.out.println("exception during creating code block : " + sciException);
                        }

                return clazz;
                }

        public boolean canGenerate() {
                if (getPropertyValue(ClientProperty.SERVICE_INTERFACE_NAME) == null) {
                        setErrorMessage("Specify valid ES Service Interface.");
                        return false;
                        }

                if (!exists(getStringPropertyValue(ClientProperty.SERVICE_INTERFACE_NAME))) {
                        setErrorMessage("Specify existing ES Service Interface.");
                        return false;
                        }

                if (ClientConstant.CUSTOM_DESCRIPTION.equals(getPropertyValue(ClientProperty.SERVICE_DESCRIPTION_TYPE))) {
                        if (getPropertyValue(ClientProperty.VOCABULARY_NAME) == null) {
                                setErrorMessage("Specify non empty vocabulary name.");
                                return false;
                                }

                        int constarintCount = 0;
                        for(Enumeration values = getProperties().properties(ClientProperty.CUSTOM_CONSTRAINT); values.hasMoreElements();) {
                                String value = (String) ((Property) values.nextElement()).getValue();
                                String propertyName = "$$" + value;

                                constarintCount++;
                                if (getPropertyValue(propertyName) == null) {
                                        setErrorMessage("Specify non empty constraint value for " + value + " constraint on the next page.");
                                        return false;
                                        }
                                }
                        if(constarintCount == 0) {
                                setErrorMessage("Specify at least one constraint.");
                                return false;
                                }
                        }
                else if (ClientConstant.XML_DESCRIPTION.equals(getPropertyValue(ClientProperty.SERVICE_DESCRIPTION_TYPE))) {
                        if (Boolean.FALSE.equals(getPropertyValue(ClientProperty.PARAMETRIZE_XMLFILE_NAME)) &&
                           (getPropertyValue(ClientProperty.XMLFILE_NAME) == null)) {
                                        setErrorMessage("Specify valid xml file name.");
                                        }
                        }

                return super.canGenerate();
                }

        protected boolean isESServiceInterface(SciClass clazz) {

                if ((clazz != null) &&
                    (clazz.hasProperty(SciProperty.INTERFACE))) {

                        SciClass esServiceClass = getSciModel().findClass(getLanguage(), DEFAULT_SERVICE_NAME);
                        if (esServiceClass == null) {
                                return false;
                                }

                        // check "extends" part.
                        SciInheritanceList inheritanceList = clazz.getExtendsList();

                        for(SciInheritanceEnumeration inheritances = inheritanceList.inheritances(); inheritances.hasMoreElements();) {
                                SciInheritance inheritance = inheritances.nextSciInheritance();

                                if (esServiceClass.equals(inheritance.getReferencedElement())) {
                                        return true;
                                        }
                                }
                        }

                return false;
                }


        protected boolean exists(String qualifiedName) {
                return getSciModel().findClass(getLanguage(), qualifiedName) != null;
                }
        }


