//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.06.02 at 04:25:47 PM CEST
//

package org.w3._2001.xmlschema;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the org.w3._2001.xmlschema package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _MinInclusive_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "minInclusive");
    private final static QName _MaxLength_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "maxLength");
    private final static QName _Sequence_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "sequence");
    private final static QName _MinLength_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "minLength");
    private final static QName _Group_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "group");
    private final static QName _AttributeGroup_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "attributeGroup");
    private final static QName _Key_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "key");
    private final static QName _All_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "all");
    private final static QName _Length_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "length");
    private final static QName _SimpleType_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "simpleType");
    private final static QName _Enumeration_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "enumeration");
    private final static QName _Choice_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "choice");
    private final static QName _FractionDigits_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "fractionDigits");
    private final static QName _MinExclusive_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "minExclusive");
    private final static QName _MaxExclusive_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "maxExclusive");
    private final static QName _Element_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "element");
    private final static QName _Unique_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "unique");
    private final static QName _ComplexType_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "complexType");
    private final static QName _MaxInclusive_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "maxInclusive");
    private final static QName _Attribute_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "attribute");
    private final static QName _AnyAttribute_QNAME = new QName("http://www.w3.org/2001/XMLSchema", "anyAttribute");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.w3._2001.xmlschema
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Selector }
     *
     */
    public Selector createSelector() {
        return new Selector();
    }

    /**
     * Create an instance of {@link Annotated }
     *
     */
    public Annotated createAnnotated() {
        return new Annotated();
    }

    /**
     * Create an instance of {@link OpenAttrs }
     *
     */
    public OpenAttrs createOpenAttrs() {
        return new OpenAttrs();
    }

    /**
     * Create an instance of {@link Annotation }
     *
     */
    public Annotation createAnnotation() {
        return new Annotation();
    }

    /**
     * Create an instance of {@link Appinfo }
     *
     */
    public Appinfo createAppinfo() {
        return new Appinfo();
    }

    /**
     * Create an instance of {@link Documentation }
     *
     */
    public Documentation createDocumentation() {
        return new Documentation();
    }

    /**
     * Create an instance of {@link Facet }
     *
     */
    public Facet createFacet() {
        return new Facet();
    }

    /**
     * Create an instance of {@link TopLevelComplexType }
     *
     */
    public TopLevelComplexType createTopLevelComplexType() {
        return new TopLevelComplexType();
    }

    /**
     * Create an instance of {@link Keybase }
     *
     */
    public Keybase createKeybase() {
        return new Keybase();
    }

    /**
     * Create an instance of {@link NumFacet }
     *
     */
    public NumFacet createNumFacet() {
        return new NumFacet();
    }

    /**
     * Create an instance of {@link ExplicitGroup }
     *
     */
    public ExplicitGroup createExplicitGroup() {
        return new ExplicitGroup();
    }

    /**
     * Create an instance of {@link ComplexContent }
     *
     */
    public ComplexContent createComplexContent() {
        return new ComplexContent();
    }

    /**
     * Create an instance of {@link ComplexRestrictionType }
     *
     */
    public ComplexRestrictionType createComplexRestrictionType() {
        return new ComplexRestrictionType();
    }

    /**
     * Create an instance of {@link ExtensionType }
     *
     */
    public ExtensionType createExtensionType() {
        return new ExtensionType();
    }

    /**
     * Create an instance of {@link TopLevelAttribute }
     *
     */
    public TopLevelAttribute createTopLevelAttribute() {
        return new TopLevelAttribute();
    }

    /**
     * Create an instance of {@link Keyref }
     *
     */
    public Keyref createKeyref() {
        return new Keyref();
    }

    /**
     * Create an instance of {@link Field }
     *
     */
    public Field createField() {
        return new Field();
    }

    /**
     * Create an instance of {@link Wildcard }
     *
     */
    public Wildcard createWildcard() {
        return new Wildcard();
    }

    /**
     * Create an instance of {@link Schema }
     *
     */
    public Schema createSchema() {
        return new Schema();
    }

    /**
     * Create an instance of {@link Include }
     *
     */
    public Include createInclude() {
        return new Include();
    }

    /**
     * Create an instance of {@link Import }
     *
     */
    public Import createImport() {
        return new Import();
    }

    /**
     * Create an instance of {@link Redefine }
     *
     */
    public Redefine createRedefine() {
        return new Redefine();
    }

    /**
     * Create an instance of {@link TopLevelSimpleType }
     *
     */
    public TopLevelSimpleType createTopLevelSimpleType() {
        return new TopLevelSimpleType();
    }

    /**
     * Create an instance of {@link NamedGroup }
     *
     */
    public NamedGroup createNamedGroup() {
        return new NamedGroup();
    }

    /**
     * Create an instance of {@link NamedAttributeGroup }
     *
     */
    public NamedAttributeGroup createNamedAttributeGroup() {
        return new NamedAttributeGroup();
    }

    /**
     * Create an instance of {@link TopLevelElement }
     *
     */
    public TopLevelElement createTopLevelElement() {
        return new TopLevelElement();
    }

    /**
     * Create an instance of {@link Notation }
     *
     */
    public Notation createNotation() {
        return new Notation();
    }

    /**
     * Create an instance of {@link Union }
     *
     */
    public Union createUnion() {
        return new Union();
    }

    /**
     * Create an instance of {@link LocalSimpleType }
     *
     */
    public LocalSimpleType createLocalSimpleType() {
        return new LocalSimpleType();
    }

    /**
     * Create an instance of {@link Any }
     *
     */
    public Any createAny() {
        return new Any();
    }

    /**
     * Create an instance of {@link All }
     *
     */
    public All createAll() {
        return new All();
    }

    /**
     * Create an instance of {@link WhiteSpace }
     *
     */
    public WhiteSpace createWhiteSpace() {
        return new WhiteSpace();
    }

    /**
     * Create an instance of {@link TotalDigits }
     *
     */
    public TotalDigits createTotalDigits() {
        return new TotalDigits();
    }

    /**
     * Create an instance of {@link Restriction }
     *
     */
    public Restriction createRestriction() {
        return new Restriction();
    }

    /**
     * Create an instance of {@link NoFixedFacet }
     *
     */
    public NoFixedFacet createNoFixedFacet() {
        return new NoFixedFacet();
    }

    /**
     * Create an instance of {@link Pattern }
     *
     */
    public Pattern createPattern() {
        return new Pattern();
    }

    /**
     * Create an instance of {@link List }
     *
     */
    public List createList() {
        return new List();
    }

    /**
     * Create an instance of {@link SimpleContent }
     *
     */
    public SimpleContent createSimpleContent() {
        return new SimpleContent();
    }

    /**
     * Create an instance of {@link SimpleRestrictionType }
     *
     */
    public SimpleRestrictionType createSimpleRestrictionType() {
        return new SimpleRestrictionType();
    }

    /**
     * Create an instance of {@link SimpleExtensionType }
     *
     */
    public SimpleExtensionType createSimpleExtensionType() {
        return new SimpleExtensionType();
    }

    /**
     * Create an instance of {@link NarrowMaxMin }
     *
     */
    public NarrowMaxMin createNarrowMaxMin() {
        return new NarrowMaxMin();
    }

    /**
     * Create an instance of {@link LocalElement }
     *
     */
    public LocalElement createLocalElement() {
        return new LocalElement();
    }

    /**
     * Create an instance of {@link LocalComplexType }
     *
     */
    public LocalComplexType createLocalComplexType() {
        return new LocalComplexType();
    }

    /**
     * Create an instance of {@link SimpleExplicitGroup }
     *
     */
    public SimpleExplicitGroup createSimpleExplicitGroup() {
        return new SimpleExplicitGroup();
    }

    /**
     * Create an instance of {@link AttributeGroupRef }
     *
     */
    public AttributeGroupRef createAttributeGroupRef() {
        return new AttributeGroupRef();
    }

    /**
     * Create an instance of {@link GroupRef }
     *
     */
    public GroupRef createGroupRef() {
        return new GroupRef();
    }

    /**
     * Create an instance of {@link Attribute }
     *
     */
    public Attribute createAttribute() {
        return new Attribute();
    }

    /**
     * Create an instance of {@link RealGroup }
     *
     */
    public RealGroup createRealGroup() {
        return new RealGroup();
    }

    /**
     * Create an instance of {@link RestrictionType }
     *
     */
    public RestrictionType createRestrictionType() {
        return new RestrictionType();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Facet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "minInclusive")
    public JAXBElement<Facet> createMinInclusive(Facet value) {
        return new JAXBElement<Facet>(_MinInclusive_QNAME, Facet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NumFacet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "maxLength")
    public JAXBElement<NumFacet> createMaxLength(NumFacet value) {
        return new JAXBElement<NumFacet>(_MaxLength_QNAME, NumFacet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link ExplicitGroup }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "sequence")
    public JAXBElement<ExplicitGroup> createSequence(ExplicitGroup value) {
        return new JAXBElement<ExplicitGroup>(_Sequence_QNAME, ExplicitGroup.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NumFacet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "minLength")
    public JAXBElement<NumFacet> createMinLength(NumFacet value) {
        return new JAXBElement<NumFacet>(_MinLength_QNAME, NumFacet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NamedGroup }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "group")
    public JAXBElement<NamedGroup> createGroup(NamedGroup value) {
        return new JAXBElement<NamedGroup>(_Group_QNAME, NamedGroup.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NamedAttributeGroup }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "attributeGroup")
    public JAXBElement<NamedAttributeGroup> createAttributeGroup(NamedAttributeGroup value) {
        return new JAXBElement<NamedAttributeGroup>(_AttributeGroup_QNAME, NamedAttributeGroup.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Keybase }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "key")
    public JAXBElement<Keybase> createKey(Keybase value) {
        return new JAXBElement<Keybase>(_Key_QNAME, Keybase.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link All }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "all")
    public JAXBElement<All> createAll(All value) {
        return new JAXBElement<All>(_All_QNAME, All.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NumFacet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "length")
    public JAXBElement<NumFacet> createLength(NumFacet value) {
        return new JAXBElement<NumFacet>(_Length_QNAME, NumFacet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TopLevelSimpleType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "simpleType")
    public JAXBElement<TopLevelSimpleType> createSimpleType(TopLevelSimpleType value) {
        return new JAXBElement<TopLevelSimpleType>(_SimpleType_QNAME, TopLevelSimpleType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NoFixedFacet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "enumeration")
    public JAXBElement<NoFixedFacet> createEnumeration(NoFixedFacet value) {
        return new JAXBElement<NoFixedFacet>(_Enumeration_QNAME, NoFixedFacet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link ExplicitGroup }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "choice")
    public JAXBElement<ExplicitGroup> createChoice(ExplicitGroup value) {
        return new JAXBElement<ExplicitGroup>(_Choice_QNAME, ExplicitGroup.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link NumFacet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "fractionDigits")
    public JAXBElement<NumFacet> createFractionDigits(NumFacet value) {
        return new JAXBElement<NumFacet>(_FractionDigits_QNAME, NumFacet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Facet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "minExclusive")
    public JAXBElement<Facet> createMinExclusive(Facet value) {
        return new JAXBElement<Facet>(_MinExclusive_QNAME, Facet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Facet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "maxExclusive")
    public JAXBElement<Facet> createMaxExclusive(Facet value) {
        return new JAXBElement<Facet>(_MaxExclusive_QNAME, Facet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TopLevelElement }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "element")
    public JAXBElement<TopLevelElement> createElement(TopLevelElement value) {
        return new JAXBElement<TopLevelElement>(_Element_QNAME, TopLevelElement.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Keybase }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "unique")
    public JAXBElement<Keybase> createUnique(Keybase value) {
        return new JAXBElement<Keybase>(_Unique_QNAME, Keybase.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TopLevelComplexType }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "complexType")
    public JAXBElement<TopLevelComplexType> createComplexType(TopLevelComplexType value) {
        return new JAXBElement<TopLevelComplexType>(_ComplexType_QNAME, TopLevelComplexType.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Facet }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "maxInclusive")
    public JAXBElement<Facet> createMaxInclusive(Facet value) {
        return new JAXBElement<Facet>(_MaxInclusive_QNAME, Facet.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TopLevelAttribute }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "attribute")
    public JAXBElement<TopLevelAttribute> createAttribute(TopLevelAttribute value) {
        return new JAXBElement<TopLevelAttribute>(_Attribute_QNAME, TopLevelAttribute.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link Wildcard }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "anyAttribute")
    public JAXBElement<Wildcard> createAnyAttribute(Wildcard value) {
        return new JAXBElement<Wildcard>(_AnyAttribute_QNAME, Wildcard.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link LocalElement }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "element", scope = Group.class)
    public JAXBElement<LocalElement> createGroupElement(LocalElement value) {
        return new JAXBElement<LocalElement>(_Element_QNAME, LocalElement.class, Group.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link GroupRef }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.w3.org/2001/XMLSchema", name = "group", scope = Group.class)
    public JAXBElement<GroupRef> createGroupGroup(GroupRef value) {
        return new JAXBElement<GroupRef>(_Group_QNAME, GroupRef.class, Group.class, value);
    }

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.compile;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.apache.maven.model.Dependency;
import org.apache.maven.model.FileSet;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import fr.fastconnect.factory.tibco.bw.maven.AbstractBWArtifactMojo;
import fr.fastconnect.factory.tibco.bw.maven.AbstractBWMojo;
import fr.fastconnect.factory.tibco.bw.maven.source.AbstractProjectsListMojo;
import fr.fastconnect.factory.tibco.bw.maven.source.alias.RepositoryModel;

/**
 *

 * This goal modifies the ".aliaslib" files of the TIBCO BusinessWorks project
 * sources to include transitive JARs dependencies.
 *

 *

 * This step can be ignored by setting includeTransitiveJARsInEAR to
 * false.
 *

 *
 * @see IncludeDependenciesInEARMojo
 * @author Mathieu Debove
 *
 */
@Mojo( name="update-alias-lib",
defaultPhase=LifecyclePhase.COMPILE )
public class UpdateAliasesLibsMojo extends AbstractBWArtifactMojo {

    protected final static String SRC_NOT_SET = "Source directory is not set. Modification of '.aliaslib' file might fail.";

	@Parameter (property="includeTransitiveJARsInEAR", defaultValue="true")
	public Boolean includeTransitiveJARsInEAR;

	/**
	 * A list of directories where this goal will look for '.aliaslib' files to
	 * update.
	 */
	@Parameter(required=false)
	public List<File> customAliasLibDirectories;

	/**
	 * Whether to keep original entries in '.aliaslib' files when updating
	 */
	@Parameter(required=false, defaultValue="true")
	public Boolean keepOriginalAliasLib;

	private List<File> aliaslibFiles; // list of ".aliaslib" files to modify
	private List<Dependency> jarDependencies; // JAR dependencies retrieved from parent class AbstractBWMojo

	@Override
	protected String getArtifactFileExtension() {
		return BWEAR_EXTENSION;
	}

	/**
	 * This method retrieves a list of ".aliaslib" files to process in the
	 * source directory (usually "target/src") which is a copy of the actual
	 * source directory used to compile the TIBCO BusinessWorks EAR.
	 */
	private List<File> initFiles() throws IOException {
		FileSet restriction = new FileSet();
		File directory = buildSrcDirectory;
		if (directory == null) {
			directory = new File(".");
			getLog().warn(SRC_NOT_SET);
		}

		getLog().debug(directory.getAbsolutePath());
		restriction.setDirectory(directory.getAbsolutePath());

		restriction.addInclude("**/*.aliaslib");

		List<File> result = AbstractProjectsListMojo.toFileList(restriction);

		if (customAliasLibDirectories != null && !customAliasLibDirectories.isEmpty()) {
			for (File customDirectory : customAliasLibDirectories) {
				getLog().debug("Looking for '.aliaslib' files in custom directory: " + customDirectory);
				FileSet customRestriction = new FileSet();
				customRestriction.setDirectory(customDirectory.getAbsolutePath());
				customRestriction.addInclude("**/*.aliaslib");
				result.addAll(AbstractProjectsListMojo.toFileList(customRestriction));
			}
		}

		getLog().debug("List of '.aliaslib' files to update: " + result);
		return result;
	}

	/**
	 * This method add an alias in the object used internally by TIBCO
	 * BusinessWorks.
	 *
	 * @param list, an object used internally by TIBCO BusinessWorks.
	 * @param aliasName, the name of the alias as normalized b
	 * {@link AbstractBWMojo}.
	 */
	private void addAlias(ArrayList<HashMap<String,Object>> list, String aliasName) {
		for (HashMap<String, Object> h : list) {
			String name = (String) h.get("name");
			if (name != null && name.equals(aliasName)) {
				return; // avoid duplicates
			}
		}
		HashMap<String, Object> h = new HashMap<String, Object>();
		h.put("isClasspathFile", Boolean.TRUE);
		h.put("name", aliasName);
		h.put("includeInDeployment", Boolean.TRUE);

		list.add(h);
	}

	@SuppressWarnings("unchecked") // unchecked because we know it's the type used by TIBCO BusinessWorks
	private ArrayList<HashMap<String, Object>> readXMLBean(RepositoryModel repositoryModel, File f) throws JAXBException, UnsupportedEncodingException {
		// retrieve the content of the XML Bean in the ".aliaslib" file
		String xmlBean = repositoryModel.getRepository().getName().getFILEALIASESLIST();

		// this XML bean is decoded to a Java object with the XMLDecoder
		XMLDecoder d = new XMLDecoder(new ByteArrayInputStream(xmlBean.getBytes(this.sourceEncoding)));
		ArrayList<HashMap<String, Object>> result = null;
		try {
			result = (ArrayList<HashMap<String, Object>>) d.readObject();
		} finally {
			d.close();
		}

		return result;
	}

	private void writeXMLBean(RepositoryModel repositoryModel, File f, ArrayList<HashMap<String, Object>> aliases) throws JAXBException, IOException {
		ByteArrayOutputStream os = new ByteArrayOutputStream();

		XMLEncoder e = new XMLEncoder(os);
		e.writeObject(aliases);
		e.close();

		String xmlBean = os.toString(this.sourceEncoding);
		os.close();

		// put back the XML Bean in the ".aliaslib" file
		repositoryModel.getRepository().getName().setFILEALIASESLIST(xmlBean);
		repositoryModel.save();
	}

	/**
	 * This method adds the JAR aliases to a ".aliaslib" file
	 *
	 * @param f, the ".aliaslib" file to update
	 * @throws MojoExecutionException
	 */
	public void processFile(File f) throws MojoExecutionException {
		try {
			RepositoryModel repositoryModel = new RepositoryModel(f);

			ArrayList<HashMap<String, Object>> aliases = readXMLBean(repositoryModel, f);

			// reset old references
			if (!keepOriginalAliasLib) {
				aliases.clear();
			}

			// adding the JAR dependencies
			for (Dependency dependency : jarDependencies) {
				addAlias(aliases, getJarAlias(dependency, false));
			}

			writeXMLBean(repositoryModel, f, aliases);
		} catch (Exception e) {
			throw new MojoExecutionException(e.getMessage(), e);
		}
	}

	public void execute() throws MojoExecutionException {
		if (
			skipCompile  || skipEARCompile ||
			(
			isCurrentGoal("bw:launch-designer") ||
		   !includeTransitiveJARsInEAR
		    )
		   &&
		    (
		    customAliasLibDirectories == null ||
		    customAliasLibDirectories.isEmpty()
		    )
		   ) {
			getLog().info(SKIPPING);
			return; // ignore
		}

		super.execute();

		try {
			jarDependencies = this.getJarDependencies();
			aliaslibFiles = initFiles(); // look for ".aliaslib" files in "target/src" folder and optional directories in 'customAliasLibDirectories'
		} catch (IOException e) {
			throw new MojoExecutionException(e.getMessage(), e);
		}

		for (File f : aliaslibFiles) {
			processFile(f);
		}
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.compile;

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

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import fr.fastconnect.factory.tibco.bw.maven.AbstractBWArtifactMojo;
import fr.fastconnect.factory.tibco.bw.maven.AbstractBWMojo;
import fr.fastconnect.factory.tibco.bw.maven.exception.BinaryMissingException;

/**
 *

 * This goal creates a TIBCO BusinessWorks Projib based on the configuration
 * given in the project's POM.
 *

 *

 * The most important parameters are:
 *

 *

 *
bw.project.library.builder : the location of the Library
 * Builder file inside the TIBCO BusinessWorks project

 *
bw.project.location : the TIBCO BusinessWorks sources
 * location relatively to the POM

 *

 *

 * Other parameters have default values set with the global values of
 * "settings.xml"
 * file.
 *

 *
 * @author Mathieu Debove
 *
 */
@Mojo( name="compile-projlib",
defaultPhase=LifecyclePhase.COMPILE )
public class CompileProjlibMojo extends AbstractBWArtifactMojo {

	protected final static String TIBCO_DESIGNER_BINARY_NOTFOUND = "The TIBCO Designer binary can't be found.";
	protected final static String BUILD_PROJLIB_FAILED = "The build of the Projlib file has failed.";
	protected final static String BUILDING_PROJLIB = "Building the Projlib...";

	/**
	 * Path to the LibBuilder relatively to the BusinessWorks project path.
	 */
	@Parameter ( property="bw.project.library.builder", required = true)
	private String libBuilder;

	/**
	 * Path to the TIBCO Designer "buildlibrary" binary.
	 *
	 */
	@Parameter ( property="buildlibrary.path", required = true)
	private File tibcoBuildLibraryPath;

	private void checkDesignerBuildLibrary() throws MojoExecutionException {
		if (tibcoBuildLibraryPath == null ||
		   !tibcoBuildLibraryPath.exists() ||
		   !tibcoBuildLibraryPath.isFile()) {
			designerBuildLibraryPathNotFound();
		}
	}

	private void designerBuildLibraryPathNotFound() throws MojoExecutionException {
		throw new BinaryMissingException(TIBCO_DESIGNER_BINARY_NOTFOUND);
	}

	protected String getArtifactFileExtension() {
		return PROJLIB_EXTENSION;
	}

	/**
	 *  This calls the "buildlibrary" binary found in TIBCO Designer to build
	 * a Projlib for the {@link AbstractBWMojo#project}, defined by the {@link CompileProjlibMojo#libBuilder}.
	 *
	 * @param outputFile, the path where the Projlib output will be created
	 * @throws MojoExecutionException
	 * @throws IOException
	 */
	private void buildProjlib(File outputFile) throws MojoExecutionException, IOException {
		checkDesignerBuildLibrary();
		assert(outputFile != null);

		ArrayList<String> arguments = new ArrayList<String>();
		arguments.add("-lib"); // path of the libbuilder relative to the BW project path
		arguments.add(libBuilder);
		arguments.add("-p"); // BW project path
		arguments.add(buildSrcDirectory.getAbsolutePath());
		arguments.add("-o"); // output file
		arguments.add(outputFile.getAbsolutePath());
		arguments.add("-x"); // overwrite the output
		if (!hideLibraryResources) {
			arguments.add("-v"); // validate the project
		}

		getLog().info(BUILDING_PROJLIB);

		ArrayList<File> tras = new ArrayList<File>();
		tras.add(tibcoBuildLibraryTRAPath);
		if (tibcoBuildLibraryUseDesignerTRA) {
			tras.add(tibcoDesignerTRAPath);
		}
		launchTIBCOBinary(tibcoBuildLibraryPath, tras, arguments, directory, BUILD_PROJLIB_FAILED);
	}

	public void execute() throws MojoExecutionException {
    	if (skipCompile || skipProjlibCompile) {
    		getLog().info(SKIPPING);

            File outputFile = getOutputFile();
           	if (outputFile != null && !outputFile.exists() && touchProjlibIfSkipped) {
           		// Projlib was not created because compilation is skipped
           		// however we "touch" the Projlib file so there is an empty Projlib file created
           		try {
           			outputFile.getParentFile().mkdirs();
					outputFile.createNewFile();
				} catch (IOException e) {
					throw new MojoExecutionException(e.getLocalizedMessage(), e);
				}
           	}
            if (outputFile != null && outputFile.exists()) {
            	attachArtifact(outputFile);
            } else {
            	getLog().warn(WARN_NO_ARTIFACT_ATTACHED);
            }
    		return;
    	}

		if (isCurrentGoal("bw:launch-designer")) {
			return; // ignore
		}

		super.execute();

		File outputFile = getOutputFile();

		try {
			buildProjlib(outputFile);
		} catch (IOException e) {
			throw new MojoExecutionException(BUILD_PROJLIB_FAILED, e);
		}

		attachArtifact(outputFile);
	}

    private void attachArtifact(File outputFile) {
        getProject().getArtifact().setFile(outputFile);
    }
}


//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.06.02 at 04:25:47 PM CEST
//

package org.xmlsoap.schemas.wsdl;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

/**
 *
Java class for tOperation complex type.
 *
 *
The following schema fragment specifies the expected content contained within this class.
 *
 *

 * <complexType name="tOperation">
 *   <complexContent>
 *     <extension base="{http://schemas.xmlsoap.org/wsdl/}tExtensibleDocumented">
 *       <sequence>
 *         <choice>
 *           <group ref="{http://schemas.xmlsoap.org/wsdl/}request-response-or-one-way-operation"/>
 *           <group ref="{http://schemas.xmlsoap.org/wsdl/}solicit-response-or-notification-operation"/>
 *         </choice>
 *       </sequence>
 *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}NCName" />
 *       <attribute name="parameterOrder" type="{http://www.w3.org/2001/XMLSchema}NMTOKENS" />
 *     </extension>
 *   </complexContent>
 * </complexType>
 *

 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "tOperation", propOrder = {
    "rest"
})
public class TOperation
    extends TExtensibleDocumented
{

    @XmlElementRefs({
        @XmlElementRef(name = "fault", namespace = "http://schemas.xmlsoap.org/wsdl/", type = JAXBElement.class),
        @XmlElementRef(name = "input", namespace = "http://schemas.xmlsoap.org/wsdl/", type = JAXBElement.class),
        @XmlElementRef(name = "output", namespace = "http://schemas.xmlsoap.org/wsdl/", type = JAXBElement.class)
    })
    protected List<JAXBElement<? extends TExtensibleAttributesDocumented>> rest;
    @XmlAttribute(name = "name", required = true)
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String name;
    @XmlAttribute(name = "parameterOrder")
    @XmlSchemaType(name = "NMTOKENS")
    protected List<String> parameterOrder;

    /**
     * Gets the rest of the content model.
     *
     *

     * You are getting this "catch-all" property because of the following reason:
     * The field name "Output" is used by two different parts of a schema. See:
     * line 217 of file:/C:/temp/tibco_xsd/bw/wsdl.xsd
     * line 209 of file:/C:/temp/tibco_xsd/bw/wsdl.xsd
     *

     * To get rid of this property, apply a property customization to one
     * of both of the following declarations to change their names:
     * Gets the value of the rest property.
     *
     *

     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a set method for the rest property.
     *
     *

     * For example, to add a new item, do as follows:
     *

     *    getRest().add(newItem);
     *

     *
     *
     *

     * Objects of the following type(s) are allowed in the list
     * {@link JAXBElement }{@code <}{@link TParam }{@code >}
     * {@link JAXBElement }{@code <}{@link TParam }{@code >}
     * {@link JAXBElement }{@code <}{@link TFault }{@code >}
     *
     *
     */
    public List<JAXBElement<? extends TExtensibleAttributesDocumented>> getRest() {
        if (rest == null) {
            rest = new ArrayList<JAXBElement<? extends TExtensibleAttributesDocumented>>();
        }
        return this.rest;
    }

    /**
     * Gets the value of the name property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *
     */
    public String getName() {
        return name;
    }

    /**
     * Sets the value of the name property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *
     */
    public void setName(String value) {
        this.name = value;
    }

    /**
     * Gets the value of the parameterOrder property.
     *
     *

     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a set method for the parameterOrder property.
     *
     *

     * For example, to add a new item, do as follows:
     *

     *    getParameterOrder().add(newItem);
     *

     *
     *
     *

     * Objects of the following type(s) are allowed in the list
     * {@link String }
     *
     *
     */
    public List<String> getParameterOrder() {
        if (parameterOrder == null) {
            parameterOrder = new ArrayList<String>();
        }
        return this.parameterOrder;
    }

}


//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.06.02 at 04:25:47 PM CEST
//

package org.xmlsoap.schemas.wsdl;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

/**
 * This object contains factory methods for each
 * Java content interface and Java element interface
 * generated in the org.xmlsoap.schemas.wsdl package.
 *
An ObjectFactory allows you to programatically
 * construct new instances of the Java representation
 * for XML content. The Java representation of XML
 * content can consist of schema derived interfaces
 * and classes representing the binding of schema
 * type definitions, element declarations and model
 * groups.  Factory methods for each of these are
 * provided in this class.
 *
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _Definitions_QNAME = new QName("http://schemas.xmlsoap.org/wsdl/", "definitions");
    private final static QName _TOperationFault_QNAME = new QName("http://schemas.xmlsoap.org/wsdl/", "fault");
    private final static QName _TOperationOutput_QNAME = new QName("http://schemas.xmlsoap.org/wsdl/", "output");
    private final static QName _TOperationInput_QNAME = new QName("http://schemas.xmlsoap.org/wsdl/", "input");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.xmlsoap.schemas.wsdl
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link TDefinitions }
     *
     */
    public TDefinitions createTDefinitions() {
        return new TDefinitions();
    }

    /**
     * Create an instance of {@link TPart }
     *
     */
    public TPart createTPart() {
        return new TPart();
    }

    /**
     * Create an instance of {@link TOperation }
     *
     */
    public TOperation createTOperation() {
        return new TOperation();
    }

    /**
     * Create an instance of {@link TTypes }
     *
     */
    public TTypes createTTypes() {
        return new TTypes();
    }

    /**
     * Create an instance of {@link TFault }
     *
     */
    public TFault createTFault() {
        return new TFault();
    }

    /**
     * Create an instance of {@link TParam }
     *
     */
    public TParam createTParam() {
        return new TParam();
    }

    /**
     * Create an instance of {@link TBindingOperation }
     *
     */
    public TBindingOperation createTBindingOperation() {
        return new TBindingOperation();
    }

    /**
     * Create an instance of {@link TBindingOperationMessage }
     *
     */
    public TBindingOperationMessage createTBindingOperationMessage() {
        return new TBindingOperationMessage();
    }

    /**
     * Create an instance of {@link TMessage }
     *
     */
    public TMessage createTMessage() {
        return new TMessage();
    }

    /**
     * Create an instance of {@link TService }
     *
     */
    public TService createTService() {
        return new TService();
    }

    /**
     * Create an instance of {@link TDocumentation }
     *
     */
    public TDocumentation createTDocumentation() {
        return new TDocumentation();
    }

    /**
     * Create an instance of {@link TBinding }
     *
     */
    public TBinding createTBinding() {
        return new TBinding();
    }

    /**
     * Create an instance of {@link TImport }
     *
     */
    public TImport createTImport() {
        return new TImport();
    }

    /**
     * Create an instance of {@link TDocumented }
     *
     */
    public TDocumented createTDocumented() {
        return new TDocumented();
    }

    /**
     * Create an instance of {@link TPortType }
     *
     */
    public TPortType createTPortType() {
        return new TPortType();
    }

    /**
     * Create an instance of {@link TPort }
     *
     */
    public TPort createTPort() {
        return new TPort();
    }

    /**
     * Create an instance of {@link TBindingOperationFault }
     *
     */
    public TBindingOperationFault createTBindingOperationFault() {
        return new TBindingOperationFault();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TDefinitions }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://schemas.xmlsoap.org/wsdl/", name = "definitions")
    public JAXBElement<TDefinitions> createDefinitions(TDefinitions value) {
        return new JAXBElement<TDefinitions>(_Definitions_QNAME, TDefinitions.class, null, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TFault }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://schemas.xmlsoap.org/wsdl/", name = "fault", scope = TOperation.class)
    public JAXBElement<TFault> createTOperationFault(TFault value) {
        return new JAXBElement<TFault>(_TOperationFault_QNAME, TFault.class, TOperation.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TParam }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://schemas.xmlsoap.org/wsdl/", name = "output", scope = TOperation.class)
    public JAXBElement<TParam> createTOperationOutput(TParam value) {
        return new JAXBElement<TParam>(_TOperationOutput_QNAME, TParam.class, TOperation.class, value);
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link TParam }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://schemas.xmlsoap.org/wsdl/", name = "input", scope = TOperation.class)
    public JAXBElement<TParam> createTOperationInput(TParam value) {
        return new JAXBElement<TParam>(_TOperationInput_QNAME, TParam.class, TOperation.class, value);
    }

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.hawk;

import static fr.fastconnect.factory.tibco.bw.maven.hawk.HawkFormatter.formatData;

import java.util.List;

import COM.TIBCO.hawk.talon.DataElement;
import COM.TIBCO.hawk.talon.MethodInvocation;
import COM.TIBCO.hawk.talon.MicroAgentData;
import COM.TIBCO.hawk.talon.MicroAgentException;

public class MethodInvocator extends AbstractMethodAction {
    private MethodInvocation methodInvocation;

	public MethodInvocator(MicroAgent microAgent) throws Exception {
		super(microAgent);
	}

    public MethodInvocator(String hawkDomain, String rvService, String rvNetwork, String rvDaemon) throws Exception {
    	super(hawkDomain, rvService, rvNetwork, rvDaemon);
    }

    public MethodInvocator(String hawkDomain, String rvService, String rvNetwork, String rvDaemon, String microAgentName) throws Exception {
    	super(hawkDomain, rvService, rvNetwork, rvDaemon, microAgentName);
    }

    @Override
    public void setMethodName(String methodName) {
    	super.setMethodName(methodName);
		methodInvocation = new MethodInvocation(methodName, null);
    }

    @Override
    public void setMethodName(String methodName, List<DataElement> arguments) {
    	super.setMethodName(methodName);
    	methodInvocation = new MethodInvocation(methodName, arguments.toArray(new DataElement[0]));
    }

	public void invocate() throws Exception {
		try {
			MicroAgentData m = getAgentManager().invoke(getMicroAgentID(), methodInvocation);
			Object maData = m.getData();
			if (maData != null) {
				formatData(maData);
			}
		} catch (MicroAgentException me) {
			System.out.println("ERROR while performing a method invocation: " + me);
			throw new Exception(me.getMessage());
		}
	}

	// Main - Usage: java ConsoleApp <hawkDomain> <rvService> <rvNetwork> <rvDaemon>
    public static void main(String[] args) {
    	MethodInvocator ca = null;

        if (args.length != 4 ) {
            System.err.println("Usage: java ConsoleApp <hawkDomain> <rvService> <rvNetwork> <rvDaemon>");
            return;
        }

        if (args.length == 4) {
			try {
				ca = new MethodInvocator(args[0],args[1],args[2],args[3],"COM.TIBCO.admin.TRA");
				ca.setMethodName("getComponentInstanceStatus");
				ca.setArguments("TEC-JMS", "TEC-JMS-IN");
//				ca.setMethodName("getFileStatusForComponentFile");
//				ca.setArguments("TEC-JMS", "TEC-JMS-IN", "C:/tibco/tra/domain/LOCAL/application/logs/TEC-JMS-TEC-JMS-IN.log");
				ca.invocate();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				System.exit(0);
			}
        }
    }
}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.packaging.pom;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import fr.fastconnect.factory.tibco.bw.maven.source.POMManager;

/**
 *

 * This goal creates a POM with "
 * bw-ear-deploy" packaging.

 * This POM will be used at deployment time.
 *

 *
 * @author Mathieu Debove
 *
 */
@Mojo( name="generate-deployment-root-pom",
defaultPhase=LifecyclePhase.PREPARE_PACKAGE )
public class GenerateRootDeploymentPOM extends AbstractPOMGenerator {

	protected final static String DEPLOYMENT_POM_CLASSIFIER = "root-deployment";
	protected final static String DEPLOYMENT_POM_GENERATION = "Generating root deployment POM in ";
	protected final static String DEPLOYMENT_POM_FAILURE = "Unable to create root deployment POM";

	protected final static String WARN_NO_PARENT = "The property 'useParent' is set but no parent was found";

	@Parameter (property="deploy.pom", required=true, defaultValue="pom.xml")
	protected String pomDeployFilename;

	/**
	 * The deployment POM template is a partial Maven POM which will be used to
	 * generate the deployment POM.
	 */
	@Parameter (property="deploy.pom.template", required=false, defaultValue="${project.basedir}/src/main/maven/deployment-pom.xml")
	protected File pomDeployTemplate;

	/**
	 * Whether to merge the deployment POM template with the built-in
	 * deployment POM.
	 */
	@Parameter (property="deploy.pom.template.merge", required=false, defaultValue="true")
	protected Boolean pomDeployTemplateMerge;

	/**
	 * Use the parent POM as the source instead of the current POM.
	 * This might be useful for the delivery POM pattern.
	 */
	@Parameter ( property = "generate.pom.use.parent", required = false, defaultValue = "false")
	protected boolean useParent;

	/**
	 * To skip the generation of the POM.
	 * This might be useful to ignore intermediate parent POM between "bw-ear"
	 * POMs and the real top level parent POM.
	 */
	@Parameter ( property = "generate.pom.root.skip", required = false, defaultValue = "true")
	protected boolean skipRootDeploymentPOM;

    /**
     * Whether to "touch" the deployment POM file when deployment POM generation
     * is skipped.

     *
     * NB: must be used with 'bw.package.skip' or 'generate.pom.standalone.skip'
     * set to true.
     */
    @Parameter(property = "generate.pom.root.skip.touch", required=false, defaultValue="false")
    protected Boolean touchRootDeploymentPOMIfSkipped;

	@Parameter
	protected List<String> excludedModules;

	@Parameter
	protected List<String> includedModules;

	/* parent definition */
	/**
	 * The groupId of the parent.
	 */
	@Parameter ( property = "generate.pom.parent.groupId", required = true)
	protected String parentGroupId;

	/**
	 * The artifactId of the parent.
	 */
	@Parameter ( property = "generate.pom.parent.artifactId", required = true)
	protected String parentArtifactId;

	/**
	 * The version of the parent.
	 */
	@Parameter ( property = "generate.pom.parent.version", required = true)
	protected String parentVersion;

	/**
	 * The suffix of artifactId of the parent.
	 */
	@Parameter ( property = "generate.pom.parent.suffix", required = true, defaultValue = "deploy")
	protected String parentArtifactSuffix;

	@Parameter(property="package.bw.applications.root", defaultValue="applications", required=true)
	public String applicationsRoot;

	/* modules */
	private List<String> getActiveModules(List<Profile> activeProfiles, Model model) {
		List<String> modules = model.getModules();

		for (Profile profile : model.getProfiles()) {
			Boolean found = false;
			for (Profile p : activeProfiles) {
				if (p.getId().equals(profile.getId())) {
					found = true;
					break;
				}
			}
			if (!found) continue;

			for (String module : profile.getModules()) {
				if (modules.indexOf(module) < 0) {
					modules.add(module);
				}
			}
		}

		return modules;
	}

	@SuppressWarnings("unchecked")
	private List<Profile> getActiveProfiles(List<MavenProject> projects) {
		List<Profile> result = new ArrayList<Profile>();
		for (MavenProject project : projects) {
			result.addAll(project.getActiveProfiles());
		}

		return result;
	}

	private Model addModules(Model model, MavenProject project) throws IOException, XmlPullParserException {
		if (model == null || project == null) return null;

		// we need to include only the active projects (see the -am command line switch for detail)
		List<MavenProject> activeProjects = getSession().getProjects();

		List<String> modules = addModules(project, activeProjects);
		for (String module : modules) {
			getLog().debug("module : " + module);
			boolean excluded = false;
			for (String exclude : excludedModules) {
				String regex = wildcardToRegex(exclude);
				if (exclude != null && Pattern.matches(regex, module)) {
					excluded = true;
					break;
				}
			}
			if (excluded) continue;
			if (includedModules.isEmpty()) {
				model.addModule(module);
			} else {
				for (String include : includedModules) {
					String regex = wildcardToRegex(include);
					if (include != null && Pattern.matches(regex, module)) {
						model.addModule(module);
//						break;
					}
				}
			}
		}

		return model;
	}

	private List<String> addModules(MavenProject project, List<MavenProject> activeProjects) throws IOException, XmlPullParserException {
		return addModules(project.getBasedir() + File.separator, project.getModel(), getActiveProfiles(activeProjects), activeProjects);
	}

	private List<String> addModules(String basedir, Model model, List<Profile> activeProfiles, List<MavenProject> activeProjects) throws IOException, XmlPullParserException {
		List<String> result = new ArrayList<String>();

		List<String> modules = getActiveModules(activeProfiles, model);

		for (String module : modules) {
			String childFileName = basedir + module + File.separator + "pom.xml";
			if (!new File(childFileName).exists()) continue;

			// load the model of the module
			Model child = POMManager.getModelFromPOM(new File(childFileName), getLog());
			if (child.getPackaging().equals(BWEAR_TYPE)) { // add POMs with "bw-ear" packaging
				if (isProjectActive(child, activeProjects) != null) { // exclude inactive projects (if -am command line switch is used)

					String relativePath = getModuleRelativePath(child);
					result.add(applicationsRoot + MODULE_SEPARATOR + relativePath);
				}
			} else if (child.getPackaging().equals(POM_TYPE)) {
				// recursively add children found in POMs with "pom" packaging
				result.addAll(addModules(basedir + module + File.separator, child, activeProfiles, activeProjects));
			}
		}

		return result;
	}

	private String getModuleRelativePath(Model child) {
		String result = child.getProperties().getProperty("assembly.relative.path");
		if (result == null || result.isEmpty()) {
			result = ".";
		}
		result += MODULE_SEPARATOR + child.getArtifactId() + MODULE_SEPARATOR + pomDeployFilename;
		return result;
	}

	private MavenProject isProjectActive(Model model, List<MavenProject> activeProjects) {
		for (MavenProject mavenProject : activeProjects) {
			String packageSkipProperty = mavenProject.getProperties().getProperty("bw.package.skip");
			boolean packageSkip = packageSkipProperty != null && packageSkipProperty.equals("true");
			if ((mavenProject.getGroupId().equals(model.getGroupId()) || (model.getGroupId() == null)) && // == null in case of [inherited] value
			    mavenProject.getArtifactId().equals(model.getArtifactId()) &&
			    (mavenProject.getVersion().equals(model.getVersion()) || (model.getVersion() == null)) && // == null in case of [inherited] value
			    !packageSkip) {
				return mavenProject;
			}
		}
		return null;
	}
	/* /modules */

	private String getArtifactSuffix() {
		if (parentArtifactSuffix != null && !parentArtifactSuffix.isEmpty()) {
			if (parentArtifactSuffix.startsWith("-")) {
				return parentArtifactSuffix;
			} else {
				return "-" + parentArtifactSuffix;
			}
		} else {
			return "";
		}
	}

	public void execute() throws MojoExecutionException {
		if (excludedModules == null) {
			excludedModules = new ArrayList<String>();
		}
		if (includedModules == null) {
			includedModules = new ArrayList<String>();
		}

		super.execute();
	}

	@Override
	protected File getOutputFile() {
		return new File(packageDirectory + File.separator + pomDeployFilename);
	}

	@Override
	protected File getTemplateFile() {
		return pomDeployTemplate;
	}

	@Override
	protected Boolean getTemplateMerge()  {
		return pomDeployTemplateMerge;
	}

	@Override
	protected String getClassifier() {
		return DEPLOYMENT_POM_CLASSIFIER;
	}

	@Override
	protected Boolean getSkipGeneratePOM() {
		return skipRootDeploymentPOM;
	}

	@Override
	protected Boolean getTouchWhenSkipped() {
		return touchRootDeploymentPOMIfSkipped;
	}

	@Override
	protected InputStream getBuiltinTemplateFile() {
		return this.getClass().getClassLoader().getResourceAsStream("deploy/pom/pom.xml");
	}

	@Override
	protected Model updateModel(Model model, MavenProject project) throws MojoExecutionException {
		model.setArtifactId(project.getArtifactId() + getArtifactSuffix());
		model.setPackaging("pom");

		updatePluginVersion(model);

		try {
			model = addModules(model, project);
		} catch (IOException e) {
			throw new MojoExecutionException(e.getLocalizedMessage(), e);
		} catch (XmlPullParserException e) {
			throw new MojoExecutionException(e.getLocalizedMessage(), e);
		}

		return model;
	}

	@Override
	protected String getGenerationMessage() {
		return DEPLOYMENT_POM_GENERATION;
	}

	@Override
	protected String getFailureMessage() {
		return DEPLOYMENT_POM_FAILURE;
	}

	@Override
	protected MavenProject getProject() {
		MavenProject project = super.getProject();

		if (useParent) {
			MavenProject parent = project.getParent();

			if (parent != null) {
				project = parent;
			} else {
				getLog().warn(WARN_NO_PARENT);
			}
		}

		return project;
	}

}


//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.01.23 at 10:11:20 AM CET
//

package com.tibco.xmlns.dd;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlType;

/**
 *
Java class for anonymous complex type.
 *
 *
The following schema fragment specifies the expected content contained within this class.
 *
 *

 * <complexType>
 *   <complexContent>
 *     <extension base="{http://www.tibco.com/xmlns/dd}DeploymentDescriptorType">
 *       <sequence>
 *         <element name="disableConfigureAtDeployment" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
 *         <element ref="{http://www.tibco.com/xmlns/dd}NVPair" maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *     </extension>
 *   </complexContent>
 * </complexType>
 *

 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "disableConfigureAtDeployment",
    "nvPair"
})
public class NameValuePairs
    extends DeploymentDescriptorType
{

    protected Boolean disableConfigureAtDeployment;
    @XmlElementRef(name = "NVPair", namespace = "http://www.tibco.com/xmlns/dd", type = JAXBElement.class)
    protected List<JAXBElement<? extends NVPairType>> nvPair;

    /**
     * Gets the value of the disableConfigureAtDeployment property.
     *
     * @return
     *     possible object is
     *     {@link Boolean }
     *
     */
    public Boolean isDisableConfigureAtDeployment() {
        return disableConfigureAtDeployment;
    }

    /**
     * Sets the value of the disableConfigureAtDeployment property.
     *
     * @param value
     *     allowed object is
     *     {@link Boolean }
     *
     */
    public void setDisableConfigureAtDeployment(Boolean value) {
        this.disableConfigureAtDeployment = value;
    }

    /**
     * Gets the value of the nvPair property.
     *
     *

     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a set method for the nvPair property.
     *
     *

     * For example, to add a new item, do as follows:
     *

     *    getNVPair().add(newItem);
     *

     *
     *
     *

     * Objects of the following type(s) are allowed in the list
     * {@link JAXBElement }{@code <}{@link NVPairType }{@code >}
     * {@link JAXBElement }{@code <}{@link NameValuePairInteger }{@code >}
     * {@link JAXBElement }{@code <}{@link NameValuePairPassword }{@code >}
     * {@link JAXBElement }{@code <}{@link NameValuePairBoolean }{@code >}
     * {@link JAXBElement }{@code <}{@link NameValuePair }{@code >}
     *
     *
     */
    public List<JAXBElement<? extends NVPairType>> getNVPair() {
        if (nvPair == null) {
            nvPair = new ArrayList<JAXBElement<? extends NVPairType>>();
        }
        return this.nvPair;
    }

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.source;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;

import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Model;
import org.apache.maven.model.Profile;
import org.apache.maven.model.inheritance.DefaultInheritanceAssembler;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.logging.Log;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

/**
 * This class handles POM file manipulation using the Maven API.
 *
 * @author Mathieu Debove
 *
 */
public class POMManager {

	/**
	 * Load a Maven {@link Model} object from a POM file.
	 *
	 * @param pom
	 * @param logger
	 * @return the model parsed from the POM file
	 * @throws XmlPullParserException
	 * @throws IOException
	 */
	public static Model getModelFromPOM(File pom, Log logger) throws IOException, XmlPullParserException {
		Model model = null;
		FileInputStream fis = null;
		InputStreamReader isr = null;
		try {
			fis = new FileInputStream(pom);
			isr = new InputStreamReader(fis, "utf-8"); // FIXME
			MavenXpp3Reader reader = new MavenXpp3Reader();
			model = reader.read(isr);
		} finally {
			try {
				isr.close();
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return model;
	}

	/**
	 * Merge a Maven {@link Model} object from a POM file to an existing Maven
	 * {@link Model} object.
	 *
	 * @param pom
	 * @param existingModel
	 * @param logger
	 * @return the existing model merged with the parsed model from the POM file
	 * @throws XmlPullParserException
	 * @throws IOException
	 */
	public static Model mergeModelFromPOM(File pom, Model existingModel, Log logger) throws IOException, XmlPullParserException {
		if (pom == null || !pom.exists() || existingModel == null || logger == null) return null;

		Model model = null;
		FileInputStream fis = null;
		InputStreamReader isr = null;
		try {
			fis = new FileInputStream(pom);
			isr = new InputStreamReader(fis, "utf-8"); // FIXME
			MavenXpp3Reader reader = new MavenXpp3Reader();
			model = reader.read(isr);
			DefaultInheritanceAssembler assembler = new DefaultInheritanceAssembler();
			assembler.assembleModelInheritance(model, existingModel, null, null);
		} finally {
			try {
				isr.close();
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return model;
	}

	/**
	 * Write a Maven {@link Model} object to a POM file.
	 *
	 * @param model
	 * @param pom
	 * @param logger
	 * @throws IOException
	 */
	public static void writeModelToPOM(Model model, File pom, Log logger) throws IOException {
		FileOutputStream fos = new FileOutputStream(pom);

		new MavenXpp3Writer().write(fos, model);

		try {
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Add the Maven dependency to a POM file.
	 *
	 * @param pom
	 * @param dependency
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static void addDependency(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		model.addDependency(dependency);

		writeModelToPOM(model, pom, logger);
	}

	/**
	 * Add the Maven dependency to a POM file (in management section).
	 *
	 * @param pom
	 * @param dependency
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static void addDependencyManagement(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		DependencyManagement dMgmt = model.getDependencyManagement();
		if (dMgmt == null) {
			model.setDependencyManagement(new DependencyManagement());
			dMgmt = model.getDependencyManagement();
		}
		dMgmt.addDependency(dependency);

		writeModelToPOM(model, pom, logger);
	}

	/**
	 * Remove the Maven dependency from a POM file.
	 *
	 * @param pom
	 * @param dependency
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static void removeDependency(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		for (Iterator<Dependency> it = model.getDependencies().iterator(); it.hasNext();){
			if (dependenciesEqual(it.next(), dependency)) {
				it.remove();
			}
		}

		writeModelToPOM(model, pom, logger);
	}

	/**
	 * Remove the Maven dependency from a POM file (in management section).
	 *
	 * @param pom
	 * @param dependency
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static void removeDependencyManagement(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		DependencyManagement dMgmt = model.getDependencyManagement();
		if (dMgmt == null) {
			model.setDependencyManagement(new DependencyManagement());
			dMgmt = model.getDependencyManagement();
		}

		for (Iterator<Dependency> it = dMgmt.getDependencies().iterator(); it.hasNext();){
			if (dependenciesEqual(it.next(), dependency)) {
				it.remove();
			}
		}

		writeModelToPOM(model, pom, logger);
	}

	private static boolean dependenciesEqual(Dependency d1, Dependency d2) {
		boolean result = true;

		if (d1 == null || d2 == null) {
			return d1 == d2;
		}

		result = result && d1.getGroupId().equals(d2.getGroupId());
		result = result && d1.getArtifactId().equals(d2.getArtifactId());
		if (d1.getVersion() != null) {
			result = result && d1.getVersion().equals(d2.getVersion());
		} else {
			result = result && (d2.getVersion() == null);
		}
		if (d1.getType() != null) {
			result = result && d1.getType().equals(d2.getType());
		} else {
			result = result && (d2.getType() == null);
		}
		if (d1.getClassifier() != null) {
			result = result && d1.getClassifier().equals(d2.getClassifier());
		} else {
			result = result && (d2.getClassifier() == null);
		}

		return result;
	}

	/**
	 * Check whether a dependency exists in a list of dependencies.
	 *
	 * @param dependency
	 * @param dependencies
	 * @return true if the dependency exists in dependencies list
	 */
	private static boolean dependencyExists(Dependency dependency, List<Dependency> dependencies) {
		for (Dependency d : dependencies) {
			if (dependenciesEqual(dependency, d)) {
				return true;
			}
		}
		return false;

	}

	/**
	 * Check whether a dependency exists in a POM.
	 *
	 * @param pom
	 * @param dependency
	 * @param logger
	 * @return true if the dependency exists in the POM
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static boolean dependencyExists(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		return dependencyExists(dependency, model.getDependencies());
	}

	/**
	 * Check whether a dependency exists in a POM (in management section).
	 *
	 * @param pom
	 * @param dependency
	 * @param logger
	 * @return true if the dependency exists in the management section of the
	 * POM
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static boolean dependencyExistsManagement(File pom, Dependency dependency, Log logger) throws IOException, XmlPullParserException {
		Model model = getModelFromPOM(pom, logger);

		DependencyManagement dMgmt = model.getDependencyManagement();
		if (dMgmt == null) {
			model.setDependencyManagement(new DependencyManagement());
			dMgmt = model.getDependencyManagement();
		}

		return dependencyExists(dependency, dMgmt.getDependencies());
	}

	public static Profile getProfile(Model model, String profileId) {
		if (model == null || profileId == null || profileId.isEmpty()) return null;
		for (Profile profile : model.getProfiles()) {
			if (profileId.equals(profile.getId())) {
				return profile;
			}
		}

		Profile result = new Profile();
		result.setId(profileId);
		model.addProfile(result);
		return result;
	}

	/**
	 * Add a project as a module.
	 *
	 * @param pom
	 * @param relativePath
	 * @param logger
	 * @throws IOException
	 * @throws XmlPullParserException
	 */
	public static void addProjectAsModule(File pom, String relativePath, String profileId, Log logger) throws IOException, XmlPullParserException {
		if (relativePath == null) return;

		Model model = getModelFromPOM(pom, logger);

		relativePath = relativePath.replace("\\", "/");

		if (profileId != null && !profileId.isEmpty()) {
			Profile p = getProfile(model, profileId);
			if (p != null) {
				p.addModule(relativePath);
			}
		} else {
			model.addModule(relativePath);
		}

		writeModelToPOM(model, pom, logger);
	}

	public static void removeProjectAsModule(File pom, String relativePath,	String profileId, Log logger) throws IOException, XmlPullParserException {
		if (relativePath == null) return;

		Model model = getModelFromPOM(pom, logger);

		relativePath = relativePath.replace("\\", "/");
		if (profileId != null && !profileId.isEmpty()) {
			Profile p = getProfile(model, profileId);
			if (p != null) {
				p.removeModule(relativePath);
			}
		} else {
			model.removeModule(relativePath);
		}

		writeModelToPOM(model, pom, logger);
	}

	/**
	 * Check whether a module exists in a POM.
	 *
	 * @param rootPOM
	 * @param relative
	 * @param log
	 * @return
	 * @throws XmlPullParserException
	 * @throws IOException
	 */
	public static boolean moduleExists(File pom, String relativePath, String profileId, Log logger) throws IOException, XmlPullParserException {
		if (relativePath == null) return false;

		Model model = getModelFromPOM(pom, logger);

		relativePath = relativePath.replace("\\", "/");

		if (profileId != null && !profileId.isEmpty()) {
			Profile p = getProfile(model, profileId);
			if (p != null) {
				return p.getModules().indexOf(relativePath) >= 0;
			}
		} else {
			return model.getModules().indexOf(relativePath) >= 0;
		}

		return false;
	}

}


/**
 * (C) Copyright 2011-2015 FastConnect SAS
 * (http://www.fastconnect.fr/) and others.
 *
 * Licensed 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 fr.fastconnect.factory.tibco.bw.maven.packaging;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.TreeSet;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.FileUtils;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.maven.shared.filtering.MavenResourcesFiltering;

import fr.fastconnect.factory.tibco.bw.maven.AbstractBWArtifactMojo;

/**
 *

 * This class defines locations of files produced by packaging phase which will
 * be used by the deploy phase.
 *

 *
 * @author Mathieu Debove
 *
 */
public abstract class AbstractPackagingMojo extends AbstractBWArtifactMojo {

	protected final static String deployedProjectNameProperty = "deploy.project.name";
	protected final static String domainNameProperty = "tibco.domain.name";
	protected final static String domainUsernameProperty = "tibco.domain.username";
	protected final static String domainPasswordProperty = "tibco.domain.password";

	protected static final String deploymentDescriptorProperty = "deploy.descriptor";
	protected static final String deploymentDescriptorFinalProperty = "deploy.descriptor.final";
	protected static final String deploymentGlobalVariablesProperty = "deploy.properties.globalVariables";
	protected static final String deploymentServicesProperty = "deploy.properties.services";
	protected static final String deploymentGlobalVariablesReferenceProperty = "deploy.properties.globalVariables.reference";
	protected static final String deploymentServicesReferenceProperty = "deploy.properties.services.reference";
	protected static final String deploymentGlobalVariablesCommonProperty = "deploy.properties.globalVariables.common";
	protected static final String deploymentServicesCommonProperty = "deploy.properties.services.common";

	@Parameter ( property=deploymentDescriptorProperty, defaultValue = "${project.package.directory}/${project.build.finalName}.xml")
	protected File deploymentDescriptor;

	@Parameter ( property=deploymentDescriptorFinalProperty, defaultValue = "${project.package.directory}/${project.build.finalName}-final.xml")
	protected File deploymentDescriptorFinal;

	@Parameter ( property=deploymentGlobalVariablesProperty, defaultValue = "${project.package.directory}/${project.build.finalName}.gv.properties")
	protected File deploymentGlobalVariables;

	@Parameter ( property=deploymentServicesProperty, defaultValue = "${project.package.directory}/${project.build.finalName}.services.properties")
	protected File deploymentServices;

	@Parameter ( property=deploymentGlobalVariablesReferenceProperty, defaultValue = "${project.package.directory}/${project.artifactId}.gv.properties")
	protected File deploymentGlobalVariablesReference;

	@Parameter ( property=deploymentServicesReferenceProperty, defaultValue = "${project.package.directory}/${project.artifactId}.services.properties")
	protected File deploymentServicesReference;

	@Parameter ( property=deploymentGlobalVariablesCommonProperty, defaultValue = "${project.package.directory}/${project.artifactId}.gv.properties")
	protected File deploymentGlobalVariablesCommon;

	@Parameter ( property=deploymentServicesCommonProperty, defaultValue = "${project.package.directory}/${project.artifactId}.services.properties")
	protected File deploymentServicesCommon;

	@Parameter ( property="ignoreReferenceFiles", defaultValue = "false" )
	protected boolean ignoreReferenceFiles;

	@Parameter ( property="ignoreCommonFiles", defaultValue = "false" )
	protected boolean ignoreCommonFiles;

	@Parameter ( property="deploy.properties.filterProperties", defaultValue = "false" , alias="filterProperties" )
	protected boolean filterProperties;

	// repoInstance
	@Parameter (property="repoSelectInstance", defaultValue="local")
	protected String repoSelectInstance;

	@Parameter (property="repoHttpTimeout", defaultValue="600")
	protected Integer repoHttpTimeout;
	@Parameter (property="repoHttpUrl", defaultValue="")
	protected String repoHttpUrl;
	@Parameter (property="repoHttpServer", defaultValue="")
	protected String repoHttpServer;
	@Parameter (property="repoHttpUser", defaultValue="")
	protected String repoHttpUser;
	@Parameter (property="repoHttpPassword", defaultValue="")
	protected String repoHttpPassword;
	@Parameter (property="repoHttpExtraPropertyFile", defaultValue="")
	protected String repoHttpExtraPropertyFile;

	@Parameter (property="repoRvTimeout", defaultValue="600")
	protected Integer repoRvTimeout;
	@Parameter (property="repoRvDiscoveryTimeout", defaultValue="10")
	protected Integer repoRvDiscoveryTimeout;
	@Parameter (property="repoRvDaemon", defaultValue="tcp:7500")
	protected String repoRvDaemon;
	@Parameter (property="repoRvService", defaultValue="7500")
	protected String repoRvService;
	@Parameter (property="repoRvNetwork", defaultValue="")
	protected String repoRvNetwork;
	@Parameter (property="repoRvRegionalSubject", defaultValue="")
	protected String repoRvRegionalSubject;
	@Parameter (property="repoRvOperationRetry", defaultValue="0")
	protected Integer repoRvOperationRetry;
	@Parameter (property="repoRvServer", defaultValue="")
	protected String repoRvServer;
	@Parameter (property="repoRvUser", defaultValue="")
	protected String repoRvUser;
	@Parameter (property="repoRvPassword", defaultValue="")
	protected String repoRvPassword;
	@Parameter (property="repoRvExtraPropertyFile", defaultValue="")
	protected String repoRvExtraPropertyFile;

	@Parameter (property="repoLocalEncoding", defaultValue="UTF-8")
	protected String repoLocalEncoding;
	//

	// monitor (applied to all <bw> services)
	@Parameter (property = "events", alias="events")
	protected Events events;

	@Parameter (property = "deploy.maxDeploymentRevision", defaultValue="-1")
	protected String maxDeploymentRevision;

	@Parameter (property = "deploy.contact", defaultValue="")
	protected String contact;

	@Parameter (property = "deploy.description", defaultValue="")
	protected String description;

    /**
     *

     * This loads a properties file into a java.util.Properties object with
     * sorted keys.

     *
     *  NB: always use keys() method to browse the properties
     *

     *
     * @param propertiesFile
     * @return
     * @throws ConfigurationException
     * @throws IOException
     */
	protected Properties loadPropertiesFile(File propertiesFile) throws ConfigurationException, IOException {
		Properties properties = new Properties() { // sorted properties
			private static final long serialVersionUID = 7793482336210629858L;

			@Override
			public synchronized Enumeration<Object> keys() {
				return Collections.enumeration(new TreeSet<Object>(super.keySet()));
			}
		};

		FileInputStream fileInputStream = new FileInputStream(propertiesFile);
		properties.load(fileInputStream);

		return properties;
	}

	@Component( role=org.apache.maven.shared.filtering.MavenResourcesFiltering.class, hint="default")
	protected MavenResourcesFiltering mavenResourcesFiltering;

	/**
	 *

	 * This saves a java.util.Properties to a file.

	 *
	 * It is possible to add a comment at the beginning of the file.
	 *

	 *
	 * @param outputFile, the File where to output the Properties
	 * @param properties, the Properties to save
	 * @param propertiesComment, the comment to add at the beginning of the file
	 * @param success, the success message
	 * @param failure, the failure message
	 * @throws MojoExecutionException
	 */
	protected void savePropertiesToFile(File outputFile, Properties properties, String propertiesComment, String success, String failure) throws MojoExecutionException {
		OutputStream outputStream = null;

		try {
			outputFile.getParentFile().mkdirs();
			outputStream = new FileOutputStream(outputFile);
			properties.store(outputStream, propertiesComment);

			if (filterProperties) {
				getLog().debug("Filtering properties files");

				File tmpDir = new File(outputFile.getParentFile(), "tmp");
				tmpDir.mkdir();
				List<Resource> resources = new ArrayList<Resource>();
				Resource r = new Resource();
				r.setDirectory(outputFile.getParentFile().getAbsolutePath());
				r.addInclude("*.properties");
				r.setFiltering(true);
				resources.add(r);

				ArrayList<Object> filters = new ArrayList<Object>();
				List<String> nonFilteredFileExtensions = new ArrayList<String>();

				MavenResourcesExecution mre = new MavenResourcesExecution(resources, tmpDir, this.getProject(), this.sourceEncoding, filters, nonFilteredFileExtensions, session);
				mavenResourcesFiltering.filterResources(mre);

				FileUtils.copyDirectory(tmpDir, outputFile.getParentFile());
				FileUtils.deleteDirectory(tmpDir);
			}

			getLog().info(success + " '" + outputFile + "'");
		} catch (Exception e) {
			throw new MojoExecutionException(failure + " '" + outputFile + "'", e);
		} finally {
			try {
				outputStream.close();
			} catch (Exception e) {
			}
		}
	}

	/**
	 * Convert an expression with wildcards to a regex.
	 *
	 * source = http://www.rgagnon.com/javadetails/java-0515.html
	 *
	 * @param wildcard
	 * @return
	 */
    protected static String wildcardToRegex(String wildcard) {
        StringBuffer s = new StringBuffer(wildcard.length());
        s.append('^');
        for (int i = 0, is = wildcard.length(); i < is; i++) {
            char c = wildcard.charAt(i);
            switch(c) {
                case '*':
                    s.append(".*");
                    break;
                case '?':
                    s.append(".");
                    break;
                    // escape special regexp-characters
                case '(': case ')': case '[': case ']': case '$':
                case '^': case '.': case '{': case '}': case '|':
                case '\\':
                    s.append("\\");
                    s.append(c);
                    break;
                default:
                    s.append(c);
                    break;
            }
        }
        s.append('$');
        return(s.toString());
    }

	public boolean skip() {
		if (skipPackage) {
			getLog().info(SKIPPING);
		}
		return skipPackage;
	}

}