package kinugasa.contents.text;

import java.io.File;
import java.util.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import kinugasa.contents.resource.ContentsFileNotFoundException;
import kinugasa.contents.resource.Freeable;
import kinugasa.contents.resource.ContentsIOException;
import kinugasa.contents.resource.IllegalXMLFormatException;
import kinugasa.contents.resource.Loadable;
import kinugasa.game.GameLog;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * XMLファイルの展開とデータの管理を行います.
 * <br>
 * XMLデータはXMLElementクラスを使用し、木構造で表現されます。
 * ロードされたXMLReaderが持つノードは、ルートの1つのみです。<br>
 * <br>
 * ロード時には、DTDの検査が行われます。DTDが到達できないパスに配置されている場合や不正な
 * DTDパスを指定した場合はCoutentsFileNotFoundExceptionが投げられます。<br>
 * <br>
 *
 * @version 1.0.0 - 2013/03/15_11:48:01.<br>
 * @author dra0211 ( <a href="mailto:d0211@live.jp">d0211@live.jp</a>&nbsp;).<br>
 * <br>
 */
public final class XMLReader extends TextIO<XMLElement> implements Freeable, Loadable {

	private static final long serialVersionUID = -2592533787944999083L;

	public XMLReader(File file) throws ContentsFileNotFoundException {
		super(file);
		if (!file.exists()) {
			throw new ContentsFileNotFoundException("file not found : [" + file.getPath() + "]");
		}
	}

	public XMLReader(String filePath) throws ContentsFileNotFoundException {
		this(new File(filePath));
	}

	private static DocumentBuilderFactory openBuilderFactory() {
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
		builderFactory.setValidating(true);
		builderFactory.setIgnoringComments(true);
		builderFactory.setIgnoringElementContentWhitespace(true);
		return builderFactory;
	}

	@Override
	public XMLReader load() throws IllegalXMLFormatException, ContentsFileNotFoundException, ContentsIOException {
		DocumentBuilderFactory builderFactory = openBuilderFactory();

		Document document = null;
		try {
			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			builder.setErrorHandler(null);
			document = builder.parse(file);
		} catch (SAXException ex) {
			throw new IllegalXMLFormatException(ex);
		} catch (ParserConfigurationException ex) {
			throw new IllegalXMLFormatException(ex);
		} catch (java.io.FileNotFoundException ex) {
			throw new ContentsFileNotFoundException(ex);
		} catch (java.io.IOException ex) {
			throw new ContentsIOException(ex);
		}
		assert document != null : "document is null";

		data.add(XMLParserUtil.createElement(document.getLastChild()));
		GameLog.printInfoIfUsing("XMLReader ロードしました[" + file.getName() + "]");
		return this;
	}

	@Override
	public XMLReader free() {
		data.clear();
		return this;
	}
	/*
	 * こんな感じ。
	 * public static void main(String[] args) {
	 * XMLReader reader = new XMLReader(System.getProperty("user.home") + "/Desktop/mapData1.xml").load();
	 * reader.printAll(System.out);
	 * System.out.println("layer 0");
	 * System.out.println(reader.getData().get(0).getElement("layer").get(0).toString());
	 * }
	 */

	@Override
	public boolean isLoaded() {
		return !data.isEmpty();
	}

	@Override
	public XMLReader add(Collection<? extends XMLElement> obj) {
		return (XMLReader) super.add(obj);
	}

	@Override
	public XMLReader add(TextIO<? extends XMLElement> other) {
		return (XMLReader) super.add(other);
	}

	@Override
	public XMLReader add(XMLElement obj) {
		return (XMLReader) super.add(obj);
	}

	@Override
	public XMLReader add(XMLElement... obj) {
		return (XMLReader) super.add(obj);
	}

	@Override
	public XMLReader clear() {
		return (XMLReader) super.clear();
	}

	@Override
	public XMLReader remove(Collection<? extends XMLElement> obj) {
		return (XMLReader) super.remove(obj);
	}

	@Override
	public XMLReader remove(TextIO<? extends XMLElement> other) {
		return (XMLReader) super.remove(other);
	}

	@Override
	public XMLReader remove(XMLElement obj) {
		return (XMLReader) super.remove(obj);
	}

	@Override
	public XMLReader remove(XMLElement... obj) {
		return (XMLReader) super.remove(obj);
	}
}
