/*
 * Forge Mod Loader
 * Copyright (c) 2012-2013 cpw.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     cpw - implementation
 */

package cpw.mods.fml.common;

import static argo.jdom.JsonNodeBuilders.aStringBuilder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import argo.jdom.JsonNode;
import argo.jdom.JsonStringNode;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import cpw.mods.fml.common.functions.ModNameFunction;
import cpw.mods.fml.common.versioning.ArtifactVersion;
import cpw.mods.fml.common.versioning.VersionParser;

/**
 * @author cpw
 *
 */
public class ModMetadata
{
    private static final class JsonStringConverter implements Function<JsonNode, Object>
    {
        public Object apply(JsonNode arg0)
        {
            if (arg0.hasElements())
            {
                return Lists.transform(arg0.getElements(), new JsonArrayConverter());
            }
            else
            {
                return arg0.getText();
            }
        }
    }

    private static final class JsonArrayConverter implements Function<JsonNode, String>
    {
        public String apply(JsonNode arg0)
        {
            return arg0.getText();
        }
    }

    public String modId;
    public String name;
    public String description;

    public String url = "";
    public String updateUrl = "";

    public String logoFile = "";
    public String version = "";
    public List<String> authorList = Lists.newArrayList();
    public String credits = "";
    public String parent = "";
    public String[] screenshots;

    public ModContainer parentMod;
    public List<ModContainer> childMods = Lists.newArrayList();

    public boolean useDependencyInformation;
    public Set<ArtifactVersion> requiredMods;
    public List<ArtifactVersion> dependencies;
    public List<ArtifactVersion> dependants;
    public boolean autogenerated;

    public ModMetadata(JsonNode node)
    {
        Map<JsonStringNode, Object> processedFields = Maps.transformValues(node.getFields(), new JsonStringConverter());
        modId = (String)processedFields.get(aStringBuilder("modid"));
        if (Strings.isNullOrEmpty(modId))
        {
            FMLLog.log(Level.SEVERE, "Found an invalid mod metadata file - missing modid");
            throw new LoaderException();
        }
        name = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("name")));
        description = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("description")));
        url = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("url")));
        updateUrl = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("updateUrl")));
        logoFile = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("logoFile")));
        version = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("version")));
        credits = Strings.nullToEmpty((String)processedFields.get(aStringBuilder("credits")));
        parent =  Strings.nullToEmpty((String)processedFields.get(aStringBuilder("parent")));
        authorList = Objects.firstNonNull(((List<String>)processedFields.get(aStringBuilder("authors"))),Objects.firstNonNull(((List<String>)processedFields.get(aStringBuilder("authorList"))), authorList));
        requiredMods = processReferences(processedFields.get(aStringBuilder("requiredMods")), HashSet.class);
        dependencies = processReferences(processedFields.get(aStringBuilder("dependencies")), ArrayList.class);
        dependants = processReferences(processedFields.get(aStringBuilder("dependants")), ArrayList.class);
        useDependencyInformation = Boolean.parseBoolean(Strings.nullToEmpty((String)processedFields.get(aStringBuilder("useDependencyInformation"))));
    }

    public ModMetadata()
    {
    }

    private <T extends Collection<ArtifactVersion>> T processReferences(Object refs, Class<? extends T> retType)
    {
        T res = null;
        try
        {
            res = retType.newInstance();
        }
        catch (Exception e)
        {
            // unpossible
        }

        if (refs == null)
        {
            return res;
        }
        for (String ref : ((List<String>)refs))
        {
            res.add(VersionParser.parseVersionReference(ref));
        }
        return res;
    }

    public String getChildModCountString()
    {
        return String.format("%d child mod%s", childMods.size(), childMods.size() != 1 ? "s" : "");
    }

    public String getAuthorList()
    {
        return Joiner.on(", ").join(authorList);
    }

    public String getChildModList()
    {
        return Joiner.on(", ").join(Lists.transform(childMods, new ModNameFunction()));
    }

    public String printableSortingRules()
    {
        return "";
    }
}
