/*
 * Copyright 2015 MovingBlocks
 *
 * 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 org.terasology.web.servlet;

import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;

import org.glassfish.jersey.server.mvc.Viewable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.module.ModuleMetadata;
import org.terasology.module.ModuleMetadataJsonAdapter;
import org.terasology.module.RemoteModuleExtension;
import org.terasology.naming.Name;
import org.terasology.version.Version;
import org.terasology.web.model.ModuleListModel;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;

/**
 * TODO Type description
 * @author Martin Steiger
 */
@Path("/modules/")
public class ModuleServlet {

    private static final Logger logger = LoggerFactory.getLogger(ModuleServlet.class);

    private final ModuleListModel model;

    private final ModuleMetadataJsonAdapter metadataWriter;

    public ModuleServlet(ModuleListModel model) {
        this.model = model;
        this.metadataWriter = new ModuleMetadataJsonAdapter();
        for (RemoteModuleExtension ext : RemoteModuleExtension.values()) {
            metadataWriter.registerExtension(ext.getKey(), ext.getValueType());
        }
    }


    @GET
    @Path("list/all")
    @Produces(MediaType.APPLICATION_JSON)
    public Response list() {
        logger.info("Requested module list");

        StreamingOutput stream = os -> {
            try (Writer writer = new OutputStreamWriter(os)) {
                writer.write("[\n");
                boolean first = true;
                for (Name name : model.findModules()) {
                    for (org.terasology.naming.Version version : model.findVersions(name)) {
                        ModuleMetadata meta = model.findLatestMetadata(name, version);
                        if (first) {
                            first = false;
                        } else {
                            writer.write(',');
                            writer.write('\n');
                        }
                        metadataWriter.write(meta, writer);
                    }
                }
                writer.write("\n]");
            }
        };
        return Response.ok(stream).build();
    }

    @GET
    @Path("show")
    @Produces(MediaType.TEXT_HTML)
    public Viewable show() {
        logger.info("Requested module list as HTML");

        Set<Name> names = model.findModules();

        // the key needs to be string, so that FreeMarker can use it for lookups
        Multimap<String, org.terasology.naming.Version> map = TreeMultimap.create();
        for (Name name : names) {
            map.putAll(name.toString(), model.findVersions(name));
        }

        ImmutableMap<Object, Object> dataModel = ImmutableMap.builder()
                .put("items", map.asMap())
                .put("version", Version.getVersion())
                .build();
        return new Viewable("/module-list.ftl", dataModel);
    }

    @GET
    @Path("show/{module}")
    @Produces(MediaType.TEXT_HTML)
    public Viewable showModule(@PathParam("module") String module) {
        logger.info("Requested module list as HTML");

        Name name = new Name(module);
        Map<String, Set<org.terasology.naming.Version>> map = Collections.singletonMap(module, model.findVersions(name));

        ImmutableMap<Object, Object> dataModel = ImmutableMap.builder()
                .put("items", map)
                .put("version", Version.getVersion())
                .build();
        return new Viewable("/module-list.ftl", dataModel);
    }

    @GET
    @Path("show/{module}/{version}")
    @Produces(MediaType.TEXT_HTML)
    public Viewable showModuleVersion(@PathParam("module") String module, @PathParam("version") String version) {
        logger.info("Requested module info");

        ModuleMetadata latest = model.findLatestMetadata(new Name(module), new org.terasology.naming.Version(version));

        ImmutableMap<Object, Object> dataModel = ImmutableMap.builder()
                .put("meta", latest)
                .put("updated", RemoteModuleExtension.getLastUpdated(latest))
                .put("downloadUrl", RemoteModuleExtension.getDownloadUrl(latest))
                .put("downloadSize", RemoteModuleExtension.getArtifactSize(latest) / 1024)
                .put("version", Version.getVersion())
                .build();

        return new Viewable("/module-info.ftl", dataModel);
    }

}

@@ -663,31 +663,8 @@
 er;%0A
-import java.io.Writer;%0A
 impo
@@ -689,16 +689,16 @@
 ctions;%0A
+
 import j
@@ -1472,16 +1472,58 @@
 ultimap;
+%0Aimport com.google.gson.stream.JsonWriter;
 %0A%0A/**%0A *
@@ -2128,17 +2128,16 @@
 %0A    %7D%0A%0A
-%0A
     @GET
@@ -2156,12 +2156,8 @@
 list
-/all
 %22)%0A 
@@ -2331,16 +2331,20 @@
    try (
+Json
 Writer w
@@ -2355,16 +2355,31 @@
 r = new 
+JsonWriter(new 
 OutputSt
@@ -2393,16 +2393,17 @@
 ter(os))
+)
  %7B%0A     
@@ -2424,19 +2424,19 @@
 ter.
-write(%22%5B%5Cn%22
+beginArray(
 );%0A 
@@ -2454,29 +2454,57 @@
     
-boolean first = true;
+writer.setIndent(%22  %22); // enable pretty printing
 %0A   
@@ -2740,242 +2740,8 @@
 n);%0A
-                        if (first) %7B%0A                            first = false;%0A                        %7D else %7B%0A                            writer.write(',');%0A                            writer.write('%5Cn');%0A                        %7D%0A
     
@@ -2863,19 +2863,17 @@
 ter.
-write(%22%5Cn%5D%22
+endArray(
 );%0A 

Use JsonWriter to write list of modules