# GovernanceArtifactConfiguration.java

    /*
     *  Copyright (c) 2005-2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
     *
     *  WSO2 Inc. 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 org.wso2.carbon.governance.api.util;

    import org.apache.axiom.om.OMElement;
    import org.wso2.carbon.registry.core.Association;
    import org.wso2.carbon.utils.component.xml.config.ManagementPermission;

    import javax.xml.namespace.QName;
    import java.util.*;

    /**
     * Configuration of a Governance Artifact
     */
    public class GovernanceArtifactConfiguration {

        private String mediaType;
        private String extension;
        private boolean hasNamespace;
        private int iconSet = 0;
        private String key;
        private String singularLabel;
        private String pluralLabel;
        private String pathExpression;
        private String lifecycle;
        private String taxonomy;
        private Map<String,Map<String,Boolean>> taxonomies;
        private String groupingAttribute;
        private OMElement uiConfigurations;
        private List<Association> relationships = new LinkedList<Association>();
        private OMElement contentDefinition;
        private String contentURL;
        private List<ManagementPermission> uiPermissions = new LinkedList<ManagementPermission>();
        private UIListConfiguration[] listConfigurations;
        private String artifactNameAttribute = "overview_name";
        private String artifactNamespaceAttribute = "overview_namespace";
        private String artifactElementRoot = "metadata";
        private String artifactElementNamespace = "http://www.wso2.org/governance/metadata";
        List<String> uniqueAttributes = new ArrayList<>();

        private static final String WIDGET_ELEMENT = "table";
        private static final String ARGUMENT_ELMENT = "field";
        private static final String ARGUMENT_NAME = "name";
        private static final String WIDGET_NAME = "name";
        private static final String TYPE_ATTRIBUTE = "type";
        private static final String MANDETORY_ATTRIBUTE = "required";
        private static final String VALIDATE_ATTRIBUTE = "validate";
        private static final String MAXOCCUR_UNBOUNDED = "unbounded";
        private static final String OPTION_TEXT_FIELD = "option-text";
        private static final String MAXOCCUR_ELEMENT = "maxoccurs";
        public static final String TEXT_FIELD = "text";
        public static final String ENTRY_FIELD = "entry";

        private Map<String, String> contextToLifeCycleMap = new HashMap<String, String>();

        /**
         * Method to obtain the media type.
         *
         * @return the media type.
         */
        public String getMediaType() {
            return mediaType;
        }

        /**
         * Method to set the media type.
         *
         * @param mediaType the media type.
         */
        public void setMediaType(String mediaType) {
            this.mediaType = mediaType;
        }

        /**
         * Method to get the content URL.
         */
        public String getContentURL() {
            return contentURL;
        }

        /**
         * Method to set the content URL.
         *
         * @param contentURL the content URL.
         */
        public void setContentURL(String contentURL) {
            this.contentURL = contentURL;
        }

        /**
         * Method to obtain the extension.
         *
         * @return the extension.
         */
        public String getExtension() {
            return extension;
        }

        /**
         * Method to set the extension.
         *
         * @param extension the extension.
         */
        public void setExtension(String extension) {
            this.extension = extension;
        }

        /**
         * Method to get whether namespace exists.
         */
        public boolean hasNamespace() {
            return hasNamespace;
        }

        /**
         * Method to set whether namespace exists.
         *
         * @param hasNamespace whether namespace exists.
         */
        public void setHasNamespace(boolean hasNamespace) {
            this.hasNamespace = hasNamespace;
        }

        /**
         * Method to obtain the icon set to be used.
         *
         * @return the icon set to be used.
         */
        public int getIconSet() {
            return iconSet;
        }

        /**
         * Method to set the icon set to be used.
         *
         * @param iconSet the icon set to be used.
         */
        public void setIconSet(int iconSet) {
            this.iconSet = iconSet;
        }

        /**
         * Returns the grouping attribute
         *
         * @return Grouping attribute name
         */
        public String getGroupingAttribute() {
            return groupingAttribute;
        }

        /**
         *
         * @param groupingAttribute attribute to be grouped from
         */
        public void setGroupingAttribute(String groupingAttribute) {
            this.groupingAttribute = groupingAttribute;
        }

        /**
         * Method to obtain the attribute that specifies the artifact name.
         *
         * @return the attribute that specifies the artifact name.
         */
        public String getArtifactNameAttribute() {
            return artifactNameAttribute;
        }

        /**
         * Method to set the attribute that specifies the artifact name.
         *
         * @param artifactNameAttribute the attribute that specifies the artifact name.
         */
        public void setArtifactNameAttribute(String artifactNameAttribute) {
            this.artifactNameAttribute = artifactNameAttribute;
        }

        /**
         * Method to obtain the attribute that specifies the artifact namespace.
         *
         * @return the attribute that specifies the artifact namespace.
         */
        public String getArtifactNamespaceAttribute() {
            return artifactNamespaceAttribute;
        }

        /**
         * Method to set the attribute that specifies the artifact namespace.
         *
         * @param artifactNamespaceAttribute the attribute that specifies the artifact namespace.
         */
        public void setArtifactNamespaceAttribute(String artifactNamespaceAttribute) {
            this.artifactNamespaceAttribute = artifactNamespaceAttribute;
        }

        public List<String> getUniqueAttributes() {
            return uniqueAttributes;
        }

        public void setUniqueAttributes(List<String> uniqueAttributes) {
            this.uniqueAttributes = uniqueAttributes;
        }

        /**
         * Method to obtain the name of the root element of an XML governance artifact.
         *
         * @return the name of the root element of an XML governance artifact.
         */
        @SuppressWarnings("unused")
        public String getArtifactElementRoot() {
            return artifactElementRoot;
        }

        /**
         * Method to set the name of the root element of an XML governance artifact.
         *
         * @param artifactElementRoot the name of the root element of an XML governance artifact.
         */
        public void setArtifactElementRoot(String artifactElementRoot) {
            this.artifactElementRoot = artifactElementRoot;
        }

        /**
         * Method to obtain the namespace of the root element of an XML governance artifact.
         *
         * @return the namespace of the root element of an XML governance artifact.
         */
        public String getArtifactElementNamespace() {
            return artifactElementNamespace;
        }

        /**
         * Method to set the namespace of the root element of an XML governance artifact.
         *
         * @param artifactElementNamespace the namespace of the root element of an XML governance
         *                                 artifact.
         */
        public void setArtifactElementNamespace(String artifactElementNamespace) {
            this.artifactElementNamespace = artifactElementNamespace;
        }

        /**
         * Method to retrieve the relationship details.
         *
         * @return the relationship details.
         */
        public Association[] getRelationshipDefinitions() {
            return relationships.toArray(new Association[relationships.size()]);
        }

        /**
         * Method to set the relationship details.
         *
         * @param relationships the relationship details.
         */
        public void setRelationshipDefinitions(Association[] relationships) {
            this.relationships = Arrays.asList(relationships);
        }

        /**
         * Method to obtain the content definition element.
         *
         * @return the content definition element.
         */
        @SuppressWarnings("unused")
        public OMElement getContentDefinition() {
            return contentDefinition;
        }

        /**
         * Method to set the content definition element.
         *
         * @param contentDefinition the content definition element.
         */
        public void setContentDefinition(OMElement contentDefinition) {
            this.contentDefinition = contentDefinition;
        }

        /**
         * Method to obtain the UI configurations element.
         *
         * @return the UI configurations element.
         */
        @SuppressWarnings("unused")
        public OMElement getUIConfigurations() {
            return uiConfigurations;
        }

        /**
         * Method to set the UI configurations element.
         *
         * @param uiConfigurations the UI configurations element.
         */
        public void setUIConfigurations(OMElement uiConfigurations) {
            this.uiConfigurations = uiConfigurations;
        }

        /**
         * Method to obtain the UI permissions element.
         *
         * @return the UI permissions element.
         */
        @SuppressWarnings("unused")
        public ManagementPermission[] getUIPermissions() {
            return uiPermissions.toArray(new ManagementPermission[uiPermissions.size()]);
        }

        /**
         * Method to set the UI permissions element.
         *
         * @param uiPermissions the UI permissions element.
         */
        public void setUIPermissions(ManagementPermission[] uiPermissions) {
            this.uiPermissions = Arrays.asList(uiPermissions);
        }

        /**
         * Method to set the configuration for the artifact list UI.
         *
         * @param listConfigurations the configuration for the artifact list UI.
         */
        public void setUIListConfigurations(OMElement listConfigurations) {
            Iterator iterator =
                    listConfigurations.getChildrenWithName(
                            new QName("column"));
            List<UIListConfiguration> configurations =
                    new LinkedList<UIListConfiguration>();
            while (iterator.hasNext()) {
                OMElement configurationElement = (OMElement) iterator.next();
                OMElement dataElement =
                        configurationElement.getFirstChildWithName(
                                new QName("data"));
                if (dataElement != null) {
                    String name = configurationElement.getAttributeValue(new QName("name"));
                    String key = dataElement.getAttributeValue(new QName("value"));
                    String type = dataElement.getAttributeValue(new QName("type"));
                    String expression = dataElement.getAttributeValue(new QName("href"));
                    if (key != null && name != null) {
                        configurations.add(new UIListConfiguration(key, type, name, expression));
                    }
                }

            }
            this.listConfigurations =
                    configurations.toArray(new UIListConfiguration[configurations.size()]);
        }

        /**
         * Method to obtain the key that can be used to locate an artifact.
         *
         * @return the key that can be used to locate an artifact.
         */
        public String getKey() {
            return key;
        }

        /**
         * Method to set the key that can be used to locate an artifact.
         *
         * @param key the key that can be used to locate an artifact.
         */
        public void setKey(String key) {
            this.key = key;
        }

        /**
         * Method to obtain the label used in singular representations of the artifact.
         *
         * @return the label used in singular representations of the artifact.
         */
        public String getSingularLabel() {
            return singularLabel;
        }

        /**
         * Method to set the label used in singular representations of the artifact.
         *
         * @param singularLabel the label used in singular representations of the artifact.
         */
        public void setSingularLabel(String singularLabel) {
            this.singularLabel = singularLabel;
        }

        /**
         * Method to obtain the label used in plural representations of the artifact.
         *
         * @return the label used in plural representations of the artifact.
         */
        public String getPluralLabel() {
            return pluralLabel;
        }

        /**
         * Method to set the label used in plural representations of the artifact.
         *
         * @param  pluralLabel the label used in plural representations of the artifact.
         */
        public void setPluralLabel(String pluralLabel) {
            this.pluralLabel = pluralLabel;
        }

        /**
         * Method to obtain the expression that can be used to compute where to store the artifact.
         *
         * @return the expression that can be used to compute where to store the artifact.
         */
        public String getPathExpression() {
            return pathExpression;
        }

        /**
         * Method to set the expression that can be used to compute where to store the artifact.
         *
         * @param pathExpression the expression that can be used to compute where to store the artifact.
         */
        public void setPathExpression(String pathExpression) {
            this.pathExpression = pathExpression;
            setUniqueAttributes();
        }

        /**
         * Method to obtain the lifecycle associated with the artifact configuration
         *
         * @return Lifecycle name associated with the artifact configuration
         */
        public String getLifecycle() {
            return lifecycle;
        }

        /**
         * Method to obtain the taxonomy associated with the artifact configuration
         *
         * @return taxonomy name associated with the artifact configuration
         */
        public Map<String, Map<String, Boolean>> getTaxonomy() {
            return taxonomies;
        }

        /**
         *
         * @param context name of the context which life cycle is needed
         * @return lifecycle name of the context. Or the default attached lifecycle
         */
        public String getLifeCycleOfContext(String context) {
            String lc = contextToLifeCycleMap.get(context);

            if(lc == null) {
                lc = getLifecycle();
            }

            return lc;
        }

        /**
         *
         * @param context context name
         * @param lcName life-cyle name
         */
        public void addLifeCycleToContext(String context, String lcName) {
            contextToLifeCycleMap.put(context, lcName);
        }

        /**
         * Method to associate lifecycle with the artifact configuration
         *
         * @param lifecycle Name of the lifecycle associated with the artifact configuration
         */
        public void setLifecycle(String lifecycle) {
            this.lifecycle = lifecycle;
        }

        /**
         * Method to associate taxonomy with the artifact configuration
         *
         * @param taxonomyName Name of the taxonomy associated with the artifact configuration
         */
        public void setTaxonomy(String taxonomyName,Boolean disable,Boolean isGlobal) {
            Map<String,Boolean> metaData = new HashMap<>();
            metaData.put("isDisable",disable);
            metaData.put("isGlobal",isGlobal);
            if (this.taxonomies == null) {
                this.taxonomies = new HashMap<>();
            }
            this.taxonomies.put(taxonomyName, metaData);
        }

        /**
         * Method to obtain the list of keys that will be used to generate the artifact list UI.
         *
         * @return the list of keys that will be used to generate the artifact list UI.
         */
        public String[] getKeysOnListUI() {
            String[] keysOnListUI = new String[listConfigurations.length];
            for (int i = 0; i < listConfigurations.length; i++) {
                keysOnListUI[i] = listConfigurations[i].getKey();
            }
            return keysOnListUI;
        }

        /**
         * Method to obtain the list of names that will be displayed on the artifact list UI.
         *
         * @return the list of names that will be displayed on the artifact list UI.
         */
        public String[] getNamesOnListUI() {
            String[] namesOnListUI = new String[listConfigurations.length];
            for (int i = 0; i < listConfigurations.length; i++) {
                namesOnListUI[i] = listConfigurations[i].getName();
            }
            return namesOnListUI;
        }

        /**
         * Method to obtain the list of types that will be used to populate the content on the artifact
         * list UI.
         *
         * @return the list of types that will be used to populate the content on the artifact list UI.
         */
        public String[] getTypesOnListUI() {
            String[] typesOnListUI = new String[listConfigurations.length];
            for (int i = 0; i < listConfigurations.length; i++) {
                typesOnListUI[i] = listConfigurations[i].getType();
            }
            return typesOnListUI;
        }

        /**
         * Method to obtain the list of expressions that will be used to populate the content on the
         * artifact list UI.
         *
         * @return the list of expressions that will be used to populate the content on the artifact
         *         list UI.
         */
        public String[] getExpressionsOnListUI() {
            String[] expressionsOnListUI = new String[listConfigurations.length];
            for (int i = 0; i < listConfigurations.length; i++) {
                expressionsOnListUI[i] = listConfigurations[i].getExpression();
            }
            return expressionsOnListUI;
        }

        private String getDataElementName(String widgetName) {
            if (widgetName == null || widgetName.length() == 0) {
                return null;
            }
            String[] nameParts = widgetName.split("_");
            String convertedName = null;
            //  making widget name camel case
            for (String namePart : nameParts) {
                int i;
                for (i = 0; i < namePart.length(); i++) {
                    char c = namePart.charAt(i);
                    if (!Character.isLetter(c) || Character.isLowerCase(c)) {
                        break;
                    }
                }
                namePart = namePart.substring(0, i).toLowerCase() + namePart.substring(i);
                if (convertedName == null) {
                    convertedName = namePart;
                } else {
                    convertedName += "_" + namePart;
                }
            }
            if (convertedName == null) {
                return null;
            }

            return convertedName.replaceAll(" ", "").replaceAll("-", "");
        }

        /**
         * Method to obtain the list of keys, in the form used in GovernanceArtifact
         * getAttributes/setAttributes methods, for attributes need to be regex validated.
         *
         * @return  list of keys in the form used in GovernanceArtifact
         *          getAttributes/setAttributes methods
         */
        public List<Map> getValidationAttributes() {
            List<Map> res = new ArrayList<Map>();

            List<String> id = new ArrayList<String>();
            Iterator it = contentDefinition.getChildrenWithName(new QName(WIDGET_ELEMENT));
            while (it.hasNext()) {
                OMElement widget = (OMElement) it.next();
                String widgetName = widget.getAttributeValue(new QName(null, ARGUMENT_NAME));
                Iterator arguments = widget.getChildrenWithLocalName(ARGUMENT_ELMENT);
                OMElement arg = null;
                while (arguments.hasNext()) {
                    arg = (OMElement) arguments.next();
                    if (ARGUMENT_ELMENT.equals(arg.getLocalName())) {
                        //check the validation fields and get the id's of them
                        String value = arg.getAttributeValue(new QName(null,
                                VALIDATE_ATTRIBUTE));
                        String isMandatory = arg.getAttributeValue(new QName(null,
                                                                             MANDETORY_ATTRIBUTE));

                        if ((value != null && !"".equals(value)) || (isMandatory != null && "true".equals(isMandatory))) {
                            String elementType = arg.getAttributeValue(new QName(null, TYPE_ATTRIBUTE));
                            String name = arg.getFirstChildWithName(new QName(null, ARGUMENT_NAME)).getText();
                            List<String> keys = new ArrayList<String>();

                            if (OPTION_TEXT_FIELD.equals(elementType)) {
                                if (MAXOCCUR_UNBOUNDED.equals(
                                        arg.getAttributeValue(new QName(null, MAXOCCUR_ELEMENT)))) {
                                    Map<String, Object> map = new HashMap<String, Object>();

                                    keys.add(getDataElementName(widgetName + "_" + ENTRY_FIELD));
                                    map.put("keys", keys);
                                    map.put("name", name);
                                    if (value != null && !"".equals(value)) {
                                        map.put("regexp", value);
                                    }
                                    if (isMandatory != null && "true".equals(isMandatory)) {
                                        map.put("isMandatory", true);
                                    }
                                    map.put("properties", "unbounded");

                                    res.add(map);
                                } else {
                                    Map<String, Object> map = new HashMap<String, Object>();

                                    keys.add(getDataElementName(widgetName + "_"  + name));
                                    keys.add(getDataElementName(widgetName + "_"  + TEXT_FIELD +
                                            name));
                                    map.put("keys", keys);
                                    map.put("name", name);
                                    if (value != null && !"".equals(value)) {
                                        map.put("regexp", value);
                                    }
                                    if (isMandatory != null && "true".equals(isMandatory)) {
                                        map.put("isMandatory", true);
                                    }

                                    res.add(map);
                                }
                            } else {
                                Map<String, Object> map = new HashMap<String, Object>();

                                keys.add(getDataElementName(widgetName + "_"  + name));
                                map.put("keys", keys);
                                map.put("name", name);
                                if (value != null && !"".equals(value)) {
                                    map.put("regexp", value);
                                }
                                if (isMandatory != null && "true".equals(isMandatory)) {
                                    map.put("isMandatory", true);
                                }

                                res.add(map);
                            }
                        }
                    }
                }
            }
            return res;
        }

        /**
         * Method to get a list of maps containing mandatory fields for a given artifact
         *
         * @return A list of maps containing mandatory fields for a given artifact
         */
        public List<Map> getMandatoryAttributes() {
            List<Map> res = new ArrayList<Map>();

            Iterator it = contentDefinition.getChildrenWithName(new QName(WIDGET_ELEMENT));
            while (it.hasNext()) {
                OMElement widget = (OMElement) it.next();
                String widgetName = widget.getAttributeValue(new QName(null, ARGUMENT_NAME));
                Iterator arguments = widget.getChildrenWithLocalName(ARGUMENT_ELMENT);
                OMElement arg = null;
                while (arguments.hasNext()) {
                    arg = (OMElement) arguments.next();
                    if (ARGUMENT_ELMENT.equals(arg.getLocalName())) {
                        //check the validation fields and get the id's of them
                        String value = arg.getAttributeValue(new QName(null,
                                                                       MANDETORY_ATTRIBUTE));

                        if (value != null && "true".equals(value)) {
                            String elementType = arg.getAttributeValue(new QName(null, TYPE_ATTRIBUTE));
                            String name = arg.getFirstChildWithName(new QName(null, ARGUMENT_NAME)).getText();
                            List<String> keys = new ArrayList<String>();

                            if (OPTION_TEXT_FIELD.equals(elementType)) {
                                if (MAXOCCUR_UNBOUNDED.equals(
                                        arg.getAttributeValue(new QName(null, MAXOCCUR_ELEMENT)))) {
                                    Map<String, Object> map = new HashMap<String, Object>();

                                    keys.add(getDataElementName(widgetName + "_" + ENTRY_FIELD));
                                    map.put("keys", keys);
                                    map.put("name", name);
                                    map.put("properties", "unbounded");

                                    res.add(map);
                                } else {
                                    Map<String, Object> map = new HashMap<String, Object>();

                                    keys.add(getDataElementName(widgetName + "_"  + name));
                                    keys.add(getDataElementName(widgetName + "_"  + TEXT_FIELD +
                                                                name));
                                    map.put("keys", keys);
                                    map.put("name", name);
                                    res.add(map);
                                }
                            } else {
                                Map<String, Object> map = new HashMap<String, Object>();

                                keys.add(getDataElementName(widgetName + "_"  + name));
                                map.put("keys", keys);
                                map.put("name", name);
                                res.add(map);
                            }
                        }
                    }
                }
            }
            return res;
        }

        protected void setUniqueAttributes() {
            if (pathExpression != null && !pathExpression.isEmpty()) {
                String[] pathSegments = pathExpression.split("/");
                for (String pathSegment : pathSegments) {
                    if (pathSegment.startsWith("@")) {
                        String attribute = pathSegment.substring(1);
                        attribute = attribute.replace("{", "").replace("}", "");
                        if(attribute.indexOf("_") == -1){
                            attribute = "overview_".concat(attribute);
                        }
                        uniqueAttributes.add(attribute);
                    }
                }
            }
        }

        private static class UIListConfiguration {

            private String key;
            private String type;
            private String name;
            private String expression;

            private UIListConfiguration(String key, String type, String name, String expression) {
                this.key = key;
                this.type = type;
                this.name = name;
                this.expression = expression;
            }

            public String getKey() {
                return key;
            }

            public String getType() {
                return type;
            }

            public String getName() {
                return name;
            }

            public String getExpression() {
                return expression;
            }
        }
    }