package be.iminds.ilabt.jfed.rspec.model;

import be.iminds.ilabt.jfed.rspec.parser.EventListExtraXml;
import be.iminds.ilabt.jfed.rspec.parser.RspecParseException;
import be.iminds.ilabt.jfed.util.GeniUrn;

import javax.annotation.Nullable;
import javax.xml.stream.XMLEventWriter;
import java.util.Date;

/**
 * RspecNodeFactory
 */
public interface RspecFactory {
    ModelRspecType getModelRspecType();

    RspecNode createNode(ModelRspec modelRspec);
    RspecNode createNodeWithClientId(ModelRspec modelRspec, String clientId);
    RspecNode copyNode(ModelRspec modelRspec, RspecNode rspecNode, RspecNode.InterfaceCopyMethod interfaceCopyMethod);
    RspecNode copyNodeIncludingInterfaces(ModelRspec newModelRspec, RspecNode node);

    /**
     * Based on extraXml and/or other properties, convert this RSpecNode into a more specialized RspecNode class (which also implements the RspecNode interface).
     *
     * @param origNode
     * @return the same node, or a new node of a more specialised class that contains the same info.
     */
    RspecNode convertToSpecialNode(RspecNode origNode) throws RspecParseException;

    RspecLink createLink(ModelRspec rspec, String addDefaultLinkType);
    RspecLink createLinkWithClientId(ModelRspec rspec, String id, String addDefaultLinkType);
    RspecLink copyLink(ModelRspec newModelRspec, RspecLink rspecLink, RspecNode.InterfaceCopyMethod interfaceCopyMethod);

    RspecInterface createInterface(RspecNode node, String id);
    RspecInterface createInterface(RspecLink link, String id);
    RspecInterface createInterface(RspecNode node, RspecLink link, String id);
    /* choose an interface name automatically */
    RspecInterface createInterface(RspecNode newRspecNode, RspecLink link);

    LinkSetting createLinkSetting(RspecInterface fromIface, RspecInterface toIface);

    ExecuteService createExecuteService(String shell, String command);
    InstallService createInstallService(String installPath, String url);
    AnsibleService createAnsibleService();

    ModelRspec createModelRspec(String rspecType);
    ModelRspec copyModelRspec(ModelRspec orig, @Nullable String newType);


    /**
     * called when the parser encounters extra XML in a node.
      * @return true if the extr aXML was processed and does not need to be stored in extraXml. False otherwise.
     */
    boolean processExtraRspecXml(ModelRspec model, EventListExtraXml extraXml) throws RspecParseException;
    /**
     * called when the parser encounters extra XML in a node.
      * @return true if the extr aXML was processed and does not need to be stored in extraXml. False otherwise.
     */
    boolean processExtraNodeXml(RspecNode node, EventListExtraXml extraXml) throws RspecParseException;
    /**
     * called when the parser encounters extra XML in a node.
      * @return true if the extr aXML was processed and does not need to be stored in extraXml. False otherwise.
     */
    boolean processExtraLinkXml(RspecLink link, EventListExtraXml extraXml) throws RspecParseException;

    void writeExtraRspecXml(ModelRspec modelRspec, XMLEventWriter eventWriter);
    void writeExtraNodeXml(RspecNode node, XMLEventWriter eventWriter);
    void writeExtraLinkXml(RspecLink link, XMLEventWriter eventWriter);


    //must have equals and hashcode  (they are very simple as all factorries of the same class will be equal.
    // This is needed because RspecSource uses RspecFactory as HashMap key.
    boolean equals(Object o);
    int hashCode();

    /** merge extra XML into the merged model. Used for merging BarrierSegments */
    void mergeExtra(ModelRspec mergedModel, ModelRspec partialRspec);

    /** called when parsing is finished, in case the factory wants to do some last change in the model.
     * Currently used for adding commands to barriers. */
    void finishParsing(ModelRspec modelRspec);

    OpenflowDataPath createOpenflowDataPath(ModelRspec rspec, EventListExtraXml allXml, String componentManagerId, String componentId, String dpidAttValue);

    Lease createLease(ModelRspec rspec, String leaseId, String clientId, Date validFromDate, Date validUntilDate, String validFromString, String validUntilString);
    Lease createLease(ModelRspec rspec, String leaseId, String clientId, Date validFromDate, Date validUntilDate);

    Channel createChannel(ModelRspec modelRspec);

    GeantTestbedType createGeantTestbedType(String name);

    AddressPool createAddressPool(ModelRspec modelRspec);
    AddressPool copyAddressPool(ModelRspec modelRspec, AddressPool addressPool);
    IPv4 createIPv4(ModelRspec modelRspec);
    IPv4 createIPv4(ModelRspec modelRspec, String address, String netmask);

    ExecuteAnsiblePlaybook createExecuteAnsibleCookbook(ModelRspec rspec, String source, String outputFilename);

    DistributeSshKeypair createDistributeSshKeypair(ModelRspec rspec, String location, GeniUrn userUrn);
}
