package org.ovirt.engine.api.rsdl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.xml.bind.JAXB;

import org.ovirt.engine.api.model.RSDL;
import org.ovirt.engine.api.utils.ApiRootLinksCreator;
import org.ovirt.engine.core.common.mode.ApplicationMode;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;

public class RsdlManager {

    private static final String RSDL_DESCRIPTION = "The oVirt RESTful API description language.";
    private static final String QUERY_PARAMETER = "?";
    private static final String SCHEMA_DESCRIPTION = "oVirt API entities schema.";
    private static final String RSDL_REL = "rsdl";
    private static final String RSDL_CONSTRAINT_PARAMETER = "rsdl";
    private static final String SCHEMA_REL = "schema";
    private static final String SCHEMA_CONSTRAINT_PARAMETER = "schema";
    private static final String SCHEMA_NAME = "ovirt-engine-api-schema.xsd";
    private static final String GENERAL_METADATA_REL = "*";
    private static final String GENERAL_METADATA_NAME = "The oVirt RESTful API generic descriptor.";
    private static final String GENERAL_METADATA_DESCRIPTION = "These options are valid for entire application.";

    private static final String METADATA_FILE_NAME = "/rsdl_metadata.yaml";

    public static void main(String[] args) throws ClassNotFoundException, IOException {
        System.out.println("Generating RSDL files...");
        String baseUri = args[0];
        String outputFileName = args[1];
        String outputFileNameGluster = args[2];

        MetaData metadata = loadMetaData();
        generateRsdlFile(metadata, baseUri, outputFileName, ApiRootLinksCreator.getAllRels(baseUri));
        generateRsdlFile(metadata, baseUri, outputFileNameGluster, ApiRootLinksCreator.getGlusterRels(baseUri));

        System.out.println("The following files have been generated: \n" + outputFileName + "\n"
                + outputFileNameGluster);
    }

    private static void generateRsdlFile(MetaData metadata, String baseUri, String outputFileName, List<String> rels)
            throws IOException, ClassNotFoundException {
        RSDL rsdl = buildRsdl(metadata, rels, baseUri);
        serializeRsdl(rsdl, outputFileName);
    }

    public static RSDL loadRsdl(ApplicationMode applicationMode) throws IOException {
        String fileName =
                applicationMode == ApplicationMode.AllModes ? ("/" + RsdlIOManager.RSDL_RESOURCE_NAME)
                        : ("/" + RsdlIOManager.GLUSTER_RSDL_RESOURCE_NAME);
        InputStream rsdlAsStrem = null;
        try {
            rsdlAsStrem = RsdlIOManager.loadAsStream(fileName);
            return JAXB.unmarshal(rsdlAsStrem, RSDL.class);
        } finally {
            if (rsdlAsStrem != null) {
                rsdlAsStrem.close();
            }
        }

    }

    private static void serializeRsdl(RSDL rsdl, String rsdlLocation) {
        JAXB.marshal(rsdl, new File(rsdlLocation));
    }

    private static RSDL buildRsdl(MetaData metadata, List<String> rels, String baseUri) throws IOException,
            ClassNotFoundException {
        RsdlBuilder builder = new RsdlBuilder(baseUri, rels, metadata)
        .description(RSDL_DESCRIPTION)
        .rel(RSDL_REL)
                .href(baseUri + QUERY_PARAMETER + RSDL_CONSTRAINT_PARAMETER)
        .schema(new SchemaBuilder()
                .rel(SCHEMA_REL)
                        .href(baseUri +
                        QUERY_PARAMETER + SCHEMA_CONSTRAINT_PARAMETER)
                .name(SCHEMA_NAME)
                .description(SCHEMA_DESCRIPTION)
                .build())
        .generalMetadata(new GeneralMetadataBuilder()
                .rel(GENERAL_METADATA_REL)
                        .href(baseUri.replace("api", "*"))
                .name(GENERAL_METADATA_NAME)
                .description(GENERAL_METADATA_DESCRIPTION)
                        .build());
        RSDL rsdl = builder.build();
        return rsdl;
    }

    private static MetaData loadMetaData() throws IOException {
        InputStream stream = RsdlManager.class.getResourceAsStream(METADATA_FILE_NAME);
        Constructor constructor = new CustomClassLoaderConstructor(Thread.currentThread().getContextClassLoader());
        Object result = new Yaml(constructor).load(stream);
        stream.close();
        MetaData metadata = (MetaData) result;
        return metadata;
    }
}

@@ -106,16 +106,44 @@
 Stream;%0A
+import java.util.ArrayList;%0A
 import j
@@ -187,16 +187,60 @@
 .JAXB;%0A%0A
+import org.apache.commons.lang.StringUtils;%0A
 import o
@@ -1397,16 +1397,82 @@
 ation.%22;
+%0A    private static final String ILLEGAL_ACTION_LINK_SUFFIX = %22/%22;
 %0A%0A    pr
@@ -1850,24 +1850,69 @@
 MetaData();%0A
+        validateActionLinksFormat(metadata);%0A
         gene
@@ -2253,32 +2253,607 @@
 luster);%0A    %7D%0A%0A
+    private static void validateActionLinksFormat(MetaData metadata) %7B%0A        List%3CString%3E illegalActionLinks = new ArrayList%3C%3E();%0A        for (Action action : metadata.getActions()) %7B%0A            String actionLink = action.getName().split(%22%5B%7C%5D%22)%5B0%5D;%0A            if (actionLink.endsWith(ILLEGAL_ACTION_LINK_SUFFIX)) %7B%0A                illegalActionLinks.add(action.getName());%0A            %7D%0A        %7D%0A%0A        if (!illegalActionLinks.isEmpty()) %7B%0A            throw new RuntimeException(%22Invalid link suffix:%5Cn%22 + StringUtils.join(illegalActionLinks, '%5Cn'));%0A        %7D%0A    %7D%0A%0A
     private stat

Validate action links are terminated properly