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

import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Server;
import be.iminds.ilabt.jfed.lowlevel.api.user_spec.UserSpec;
import be.iminds.ilabt.jfed.rspec.parser.ExtraXml;
import be.iminds.ilabt.jfed.util.GeniUrn;

import javax.annotation.Nullable;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * ModelRspec
 */
public interface ModelRspec {
    /*
     * General info
     */

    ModelRspecType getModelRspecType();

    void setParseData(String schemaLocation, String defaultNamespace, Map<String, String> namespaces);

    @Nullable
    String getSchemaLocation();

    @Nullable
    String getOrigDefaultNamespace();

    Map<String, String> getNameSpaceInfo();

    List<GeniUrn> getAllComponentManagerUrns();

    /*
     * Nodes
     */


    void addNode(RspecNode node);

    /**
     * Deletes a node and all interfaces attached to it. If a link becomes surplus, it is removed also.
     *
     * @param node
     */
    void deleteNode(RspecNode node);

    List<? extends RspecNode> getNodes();

    List<? extends RspecNode> getNodesByAuthority(Server server);

    @Nullable
    RspecNode getNodeByUniqueId(String id);

    @Nullable
    RspecNode getNodeByClientId(String id);

    @Nullable
    RspecNode getNodeByComponentId(String id);

    /*
     * Links
     */

    void addLink(RspecLink link);

    /**
     * Removes the link from the Rspec
     *
     * @param link
     */
    void deleteLink(RspecLink link);

    List<? extends RspecLink> getLinks();

    @Nullable
    RspecLink getLinkByClientId(String id);

    @Nullable
    RspecLink getLinkByUniqueId(String id);

    @Nullable
    RspecInterface getInterfaceByUniqueId(String uniqueId);

    @Nullable
    RspecInterface getInterfaceByClientId(String clientId);

    /*
     * OpenFlow DataPaths
     */

    void addOpenflowDataPath(OpenflowDataPath dp);

    List<? extends OpenflowDataPath> getOpenflowDataPaths();

    /*
     * Leases (NITOS-style reservations)
     */

    void addLease(Lease lease);

    List<? extends Lease> getLeases();

    /*
     * (Wireless) Channels
     */

    void addChannel(Channel channel);
    boolean deleteChannel(Channel channel);

    List<? extends Channel> getChannels();

    @Nullable
    Channel getChannelByComponentId(GeniUrn componentId);

    /*
     * Geant Testbed Service
     */

    void addGeantTestbedType(GeantTestbedType gtt);

    List<? extends GeantTestbedType> getGeantTestbedTypes();

    /*
     * Address Pool
     */

    void addAddressPool(AddressPool addressPool);
    boolean deleteAddressPool(AddressPool addressPool);
    List<? extends AddressPool> getAddressPools();
    AddressPool getAddressPoolByClientId(String clientId);


    /*
     * ExecuteAnsibleCookbook
     */

    void addExecuteAnsiblePlaybook(ExecuteAnsiblePlaybook executeAnsiblePlaybook);
    boolean deleteExecuteAnsiblePlaybook(ExecuteAnsiblePlaybook executeAnsiblePlaybook);
    List<? extends ExecuteAnsiblePlaybook> getExecuteAnsiblePlaybooks();
    /*
     * DistributeSshKeypair
     */

    void addDistributeSshKeypair(DistributeSshKeypair distributeSshKeypair);
    boolean deleteDistributeSshKeypair(DistributeSshKeypair distributeSshKeypair);
    List<? extends DistributeSshKeypair> getDistributeSshKeypairs();



    List<UserSpec> getSshKeys();

    void setSshKeys(List<UserSpec> newKeys);

    String nextLinkName();

    String nextNodeName();

    String getType();

    String nextIfaceName(RspecNode node);



    List<ExtraXml> getExtraXml();

    void setExtraXml(List<ExtraXml> extraXml);

    /**
     * For the moment, this does nothing more than call toGeni3RequestRspec_internal and write Xml To string.
     * Later, this can be edited to handle special cases in the geni request rspec v3 generation.
     * <p/>
     * only the PLE case is handled now, but it works automatically, without a need to specify it.
     */
    String toGeni3Rspec(RequestRspecSpecialCases specialCase);

    String toGeni3Rspec();

    @Nullable
    Date getExpires() throws ParseException;

    void setExpires(Date expires);

    String getExpiresString();

    void setExpires(String expires);

    /* return or set to null null means tag not present in rspec xml */
    Integer getRoutableAddressesAvailable();

    Integer getRoutableAddressesConfigured();

    void setRoutableAddressesAvailable(Integer i);

    void setRoutableAddressesConfigured(Integer i);

    GeantTestbedType getGeantTestbedTypeByName(String geantTestbedTypeName);

    Integer getMultiplexFactor();
    void setMultiplexFactor(Integer multiplexFactor);

    enum RequestRspecSpecialCases {NONE, PLE, NITOS, NITOS_NO_E_NODE_B_HACK }

    ModelRspec copy();
}
