package charactermanaj.model.io;

import static charactermanaj.util.XMLUtilities.*;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import charactermanaj.model.CustomLayerOrder;
import charactermanaj.model.CustomLayerOrderKey;
import charactermanaj.model.Layer;
import charactermanaj.model.PartsCategory;
import charactermanaj.model.PartsCategoryResolver;

public class CustomLayerOrderXMLReader {

	private PartsCategoryResolver categoryResolver;

	public CustomLayerOrderXMLReader(PartsCategoryResolver categoryResolver) {
		if (categoryResolver == null) {
			throw new NullPointerException("categories is required.");
		}
		this.categoryResolver = categoryResolver;
	}

	public Map<CustomLayerOrderKey, List<CustomLayerOrder>> read(InputStream is) throws IOException {
		if (is == null) {
			throw new IllegalArgumentException();
		}

		Map<CustomLayerOrderKey, List<CustomLayerOrder>> map =
				new TreeMap<CustomLayerOrderKey, List<CustomLayerOrder>>();

		Document doc = loadDocument(is);
		String lang = Locale.getDefault().getLanguage();

		try {
			Element docElm = doc.getDocumentElement();
			if (!"custom-layer-orders".equals(docElm.getNodeName())) {
				throw new IOException("Invalid Format.");
			}
			String ns = docElm.getNamespaceURI();
			if (ns == null || !ns.startsWith(CustomLayerOrderXMLWriter.NS)) {
				throw new IOException("unsupported xml format");
			}

			String docVersion = docElm.getAttribute("version").trim();
			if (!CustomLayerOrderXMLWriter.VERSION_SIG_1_0.equals(docVersion)) {
				throw new IOException("unsupported version: " + docVersion);
			}

			for (Element elmPattern : getChildElements(docElm, "pattern")) {
				String id = elmPattern.getAttribute("id");
				String patternName = elmPattern.getAttribute("name");

				if (id == null || id.length() == 0) {
					id = patternName; // idが省略されている場合はnameで代用する
				}

				Map<String, String> localizedNames = new HashMap<String, String>();
				localizedNames.put(CustomLayerOrderKey.DEFAULT_NAME_KEY, patternName);

				for (Element elmLocalizedName : getChildElements(elmPattern, "localized-name")) {
					String localizedLang = elmLocalizedName.getAttribute("lang");
					String localizedName = elmLocalizedName.getAttribute("name");
					localizedNames.put(localizedLang, localizedName);
					if (lang.equals(localizedLang)) {
						// langが一致すれば、その名前を優先する
						patternName = localizedName;
					}
				}

				List<CustomLayerOrder> orders = new ArrayList<CustomLayerOrder>();
				for (Element elmMapping : getChildElements(elmPattern, "mapping")) {
					String categoryId = elmMapping.getAttribute("category");
					String layerId = elmMapping.getAttribute("layer");
					float layerOrder = Float.parseFloat(elmMapping.getAttribute("order"));

					PartsCategory category = categoryResolver.getPartsCategory(categoryId);
					if (category != null) {
						Layer layer = category.getLayer(layerId);
						if (layer != null) {
							CustomLayerOrder order = new CustomLayerOrder();
							order.setCategory(category);
							order.setLayer(layer);
							order.setLayerOrder(layerOrder);
							orders.add(order);
						}
					}
				}

				CustomLayerOrderKey patternKey = new CustomLayerOrderKey(id, patternName, localizedNames);
				map.put(patternKey, orders);
			}

		} catch (RuntimeException ex) {
			IOException ex2 = new IOException("CustomLayerOrderXML invalid format.");
			ex2.initCause(ex);
			throw ex2;
		}

		return map;
	}

}
