/**
 * This file is part of the Meeds project (https://meeds.io/).
 *
 * Copyright (C) 2020 - 2025 Meeds Association contact@meeds.io
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.exoplatform.portal.resource;

import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import org.exoplatform.component.test.AbstractGateInTest;
import org.exoplatform.web.application.javascript.DependencyDescriptor;
import org.exoplatform.web.application.javascript.Javascript;
import org.exoplatform.web.application.javascript.JavascriptConfigParser;
import org.exoplatform.web.application.javascript.ScriptResourceDescriptor;
import org.gatein.portal.controller.resource.ResourceId;
import org.gatein.portal.controller.resource.ResourceScope;
import org.gatein.portal.controller.resource.script.Module.Local.Content;

public class TestParser extends AbstractGateInTest {

    public void testShared() throws Exception {
        String config = "" + "<gatein-resources>" + "<module>" + "<name>foo</name>" + "<script>" + "<name>foo_module</name>"
                + "<path>/foo_module.js</path>" + "</script>" + "<depends>" + "<module>bar</module>" + "</depends>"
                + "<depends>" + "<module>juu</module>" + "</depends>" + "</module>" +

                "<scripts>" + "<name>foo_scripts</name>" + "<script>" + "<name>foo_module</name>"
                + "<path>/foo_module.js</path>" + "</script>" + "<depends>" + "<scripts>bar</scripts>" + "</depends>"
                + "<depends>" + "<scripts>juu</scripts>" + "</depends>" + "</scripts>" +

                "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(2, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);
        assertEquals(new ResourceId(ResourceScope.SHARED, "foo"), desc.getId());
        assertNull(desc.getAlias());
        assertEquals(Arrays.asList(new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "bar")),
                new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "juu"))), desc.getDependencies());

        desc = scripts.get(1);
        assertEquals(new ResourceId(ResourceScope.SHARED, "foo_scripts"), desc.getId());
        assertEquals(Arrays.asList(new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "bar")),
                new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "juu"))), desc.getDependencies());
    }

    public void testPortlet() throws Exception {
        String config = "" + "<gatein-resources>" + "<portlet>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>foo_module</name>" + "<path>/foo_module.js</path>" + "</script>" + "<depends>"
                + "<module>bar</module>" + "</depends>" + "<depends>" + "<module>juu</module>" + "</depends>" + "</module>"
                + "</portlet>" + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(1, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);
        assertEquals(new ResourceId(ResourceScope.PORTLET, "mypath/foo"), desc.getId());
        assertNull(desc.getAlias());
        assertEquals(Arrays.asList(new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "bar")),
                new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "juu"))), desc.getDependencies());
    }

    public void testPortal() throws Exception {
        String config = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>foo_module</name>" + "<path>/foo_module.js</path>" + "</script>" + "<depends>"
                + "<module>bar</module>" + "</depends>" + "<depends>" + "<module>juu</module>" + "</depends>" + "</module>"
                + "</portal>" + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(1, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);
        assertEquals(new ResourceId(ResourceScope.PORTAL, "foo"), desc.getId());
        assertNull(desc.getAlias());
        assertEquals(Arrays.asList(new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "bar")),
                new DependencyDescriptor(new ResourceId(ResourceScope.SHARED, "juu"))), desc.getDependencies());
    }

    public void testModules() throws Exception {
        String config = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>local_module</name>" + "<path>/local_module.js</path>" + "</script>" + "</module>" + "</portal>"
                + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(1, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);

        List<Javascript> modules = desc.getModules();
        assertEquals(1, modules.size());

        Javascript local = modules.get(0);
        assertTrue(local instanceof Javascript.Local);
        assertEquals("/local_module.js", ((Javascript.Local) local).getContents()[0].getSource());
    }

    public void testExclude() throws Exception {
        String config = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>local_module</name>" + "<path>/local_module.js</path>" + "</script>" + "</module>" + "</portal>"
                + "</gatein-resources>";
        String configExclude = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>local_module</name>" + "<minify>false</minify><path>/local_module.js</path>" + "</script>" + "</module>" + "</portal>"
                + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        //by default, the script will be minified
        ScriptResourceDescriptor desc = scripts.get(0);
        List<Javascript> modules = desc.getModules();
        Javascript local = modules.get(0);
        assertTrue(((Javascript.Local) local).isMinify());

        //exclude script from compressor
        parser = new JavascriptConfigParser("/mypath");
        scripts = parser.parseConfig(new ByteArrayInputStream(configExclude.getBytes("UTF-8")));
        desc = scripts.get(0);
        modules = desc.getModules();
        local = modules.get(0);
        assertTrue(local instanceof Javascript.Local);
        assertFalse(((Javascript.Local) local).isMinify());
    }

    public void testResourceBundle() throws Exception {
        String config = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>" + "<script>"
                + "<name>foo_module</name>" + "<path>/foo_module.js</path>" + "<resource-bundle>my_bundle</resource-bundle>"
                + "</script>" + "</module>" + "</portal>" + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(1, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);
        assertEquals(new ResourceId(ResourceScope.PORTAL, "foo"), desc.getId());
        assertEquals(1, desc.getModules().size());
        Javascript.Local js = (Javascript.Local) desc.getModules().get(0);
        assertEquals("my_bundle", js.getResourceBundle());
    }

    public void testSupportedLocales() throws Exception {
        String config = "" + "<gatein-resources>" + "<portal>" + "<name>foo</name>" + "<module>"
                + "<supported-locale>EN</supported-locale>" + "<supported-locale>FR-fr</supported-locale>" + "</module>"
                + "</portal>" + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        assertEquals(1, scripts.size());
        ScriptResourceDescriptor desc = scripts.get(0);
        List<Locale> locales = desc.getSupportedLocales();
        assertEquals(Arrays.asList(Locale.ENGLISH, Locale.FRANCE), locales);
    }

    public void testRemoteResource() throws Exception {

        String validConfig = ""
                + "<gatein-resources xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.exoplatform.org/xml/ns/gatein_resources_1_4 http://www.exoplatform.org/xml/ns/gatein_resources_1_4\" xmlns=\"http://www.exoplatform.org/xml/ns/gatein_resources_1_4\">"
                + "<module><name>foo</name><url>http://jquery.com/jquery.js</url></module>" + "</gatein-resources>";

        JavascriptConfigParser parser = new JavascriptConfigParser("mypath");
        List<ScriptResourceDescriptor> descs = parser.parseConfig(new ByteArrayInputStream(validConfig.getBytes("UTF-8")));

        assertEquals(1, descs.size());
        ScriptResourceDescriptor desc = descs.get(0);
        List<Javascript> scripts = desc.getModules();
        assertEquals(1, scripts.size());
        assertTrue(scripts.get(0) instanceof Javascript.Remote);
    }

    public void testAlias() throws Exception {
        String config = "" + "<gatein-resources>" + "<module>" + "<name>foo</name>" + "<as>f</as>" + "<depends>"
                + "<module>bar</module>" + "<as>b</as>" + "</depends>" + "</module>" + "</gatein-resources>";

        //
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        ScriptResourceDescriptor desc = scripts.get(0);
        assertEquals("f", desc.getAlias());
        assertEquals("b", desc.getDependencies().get(0).getAlias());

        config = "" + "<gatein-resources>" + "<portal>" + "<name>zoo</name>" + "<as>z</as>" + "<module>" + "<depends>"
                + "<module>zozo</module>" + "<as>zz</as>" + "</depends>" + "</module>" + "</portal>" + "</gatein-resources>";

        List<ScriptResourceDescriptor> ptScripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));
        ScriptResourceDescriptor portalDesc = ptScripts.get(0);
        assertEquals("z", portalDesc.getAlias());
        assertEquals("zz", portalDesc.getDependencies().get(0).getAlias());
    }

    public void testLoadGroup() throws Exception {
        String config = "" + "<gatein-resources>" + "<module>" + "<name>foo_module</name>"
                + "<load-group>foo_group</load-group>" + "<script>" + "<name>foo_module</name>" + "<path>/foo_module.js</path>"
                + "</script>" + "</module>" +

                "<portal>" + "<name>foo_portal</name>" + "<module>" + "<load-group>foo_group</load-group>" + "<script>"
                + "<name>foo_portal</name>" + "<path>/foo_portal.js</path>" + "</script>" + "</module>" + "</portal>" +

                "<portlet>" + "<name>foo_portlet</name>" + "<module>" + "<load-group>foo_group</load-group>" + "<script>"
                + "<name>foo_portlet</name>" + "<path>/foo_portlet.js</path>" + "</script>" + "</module>" + "</portlet>"
                + "</gatein-resources>";

        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));

        assertEquals(3, scripts.size());
        for (ScriptResourceDescriptor des : scripts) {
            assertEquals("foo_group", des.getGroup());
        }
    }

    public void testLoadGroupRestriction() throws Exception {
        String config = "" + "<gatein-resources>" + "<scripts>" + "<name>foo_scripts</name>"
                + "<load-group>foo_group</load-group>" + "<script>" + "<name>foo_module</name>" + "<path>/foo_module.js</path>"
                + "</script>" + "</scripts>" +

                "<module>" + "<name>foo_module</name>" + "<load-group>foo_group</load-group>" + "<url>testURL</url>"
                + "</module>" + "</gatein-resources>";
        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));

        assertEquals(2, scripts.size());
        for (ScriptResourceDescriptor des : scripts) {
            assertNull(des.getGroup());
        }
    }

    public void testAdapter() throws Exception {
        String config = "" + "<gatein-resources>" + "<module>" + "<name>foo_module</name>" + "<script><name>foo</name>"
                + "<adapter>aaa;<include>/foo_module.js</include>bbb;</adapter>" + "</script>" + "</module>"
                + "</gatein-resources>";

        JavascriptConfigParser parser = new JavascriptConfigParser("/mypath");
        List<ScriptResourceDescriptor> scripts = parser.parseConfig(new ByteArrayInputStream(config.getBytes("UTF-8")));

        ScriptResourceDescriptor des = scripts.get(0);
        Javascript.Local module = (Javascript.Local) des.getModules().get(0);
        Content[] contents = module.getContents();

        assertNotNull(contents);
        assertEquals(3, contents.length);
        assertEquals("aaa;", contents[0].getSource());
        assertFalse(contents[0].isPath());
        assertEquals("/foo_module.js", contents[1].getSource());
        assertTrue(contents[1].isPath());
    }
}
