/*******************************************************************************
 * Copyright (c) 2008 IGA Tosiki, NTT DATA BUSINESS BRAINS Corp.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IGA Tosiki (NTT DATA BUSINESS BRAINS Corp.) - initial API and implementation
 *******************************************************************************/
/*
 * blanco Framework
 * Copyright (C) 2008 NTT DATA BUSINESS BRAINS CORPORATION
 * 
 * This library 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 2.1 of the License, or (at your option) any later version.
 */
package blanco.xliff;

import java.io.File;
import java.io.OutputStream;

import blanco.commons.util.BlancoStringUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTarget;
import blanco.xliff.valueobject.BlancoXliffTool;
import blanco.xliff.valueobject.BlancoXliffTransUnit;
import blanco.xml.bind.BlancoXmlMarshaller;
import blanco.xml.bind.valueobject.BlancoXmlAttribute;
import blanco.xml.bind.valueobject.BlancoXmlCharacters;
import blanco.xml.bind.valueobject.BlancoXmlDocument;
import blanco.xml.bind.valueobject.BlancoXmlElement;

public class BlancoXliffSerializer {
    private BlancoXmlCharacters charNewLineWithIndent0 = null;

    private BlancoXmlCharacters charNewLineWithIndent2 = null;

    private BlancoXmlCharacters charNewLineWithIndent4 = null;

    private BlancoXmlCharacters charNewLineWithIndent6 = null;

    private BlancoXmlCharacters charNewLineWithIndent8 = null;

    private BlancoXmlCharacters charNewLineWithIndent10 = null;

    public BlancoXliffSerializer() {
        charNewLineWithIndent0 = new BlancoXmlCharacters();
        charNewLineWithIndent2 = new BlancoXmlCharacters();
        charNewLineWithIndent4 = new BlancoXmlCharacters();
        charNewLineWithIndent6 = new BlancoXmlCharacters();
        charNewLineWithIndent8 = new BlancoXmlCharacters();
        charNewLineWithIndent10 = new BlancoXmlCharacters();
        charNewLineWithIndent0.setValue("\n");
        charNewLineWithIndent2.setValue("\n  ");
        charNewLineWithIndent4.setValue("\n    ");
        charNewLineWithIndent6.setValue("\n      ");
        charNewLineWithIndent8.setValue("\n        ");
        charNewLineWithIndent10.setValue("\n          ");
    }

    /**
     * XLIFF情報をストリームに出力します。
     * 
     * @param argXliff
     * @param outStream
     */
    public void serialize(final BlancoXliff argXliff,
            final OutputStream outStream) {
        new BlancoXmlMarshaller().marshal(valueObject2Document(argXliff),
                outStream);
    }

    /**
     * XLIFF情報をファイルに出力します。
     * 
     * @param argXliff
     * @param argFileTarget
     */
    public void serialize(final BlancoXliff argXliff, final File argFileTarget) {
        new BlancoXmlMarshaller().marshal(valueObject2Document(argXliff),
                argFileTarget);
    }

    /**
     * 与えられたXLIFF情報から blancoXml DOMツリーを作成します。
     * 
     * @param argXliff
     * @return
     */
    public BlancoXmlDocument valueObject2Document(final BlancoXliff argXliff) {
        final BlancoXmlDocument document = new BlancoXmlDocument();

        final BlancoXmlElement eleXliff = new BlancoXmlElement();
        eleXliff.setQName("xliff");
        document.getChildNodes().add(eleXliff);

        {
            final BlancoXmlAttribute attr = new BlancoXmlAttribute();
            eleXliff.getAtts().add(attr);
            attr.setQName("version");
            attr.setValue(argXliff.getVersion());
        }

        eleXliff.getChildNodes().add(charNewLineWithIndent2);

        final BlancoXmlElement eleFile = new BlancoXmlElement();
        eleXliff.getChildNodes().add(eleFile);
        eleFile.setQName("file");

        {
            final BlancoXmlAttribute original = new BlancoXmlAttribute();
            eleFile.getAtts().add(original);
            original.setQName("original");
            original.setValue("");
            // TODO fileの内容調整。

            final BlancoXmlAttribute sourceLanguage = new BlancoXmlAttribute();
            eleFile.getAtts().add(sourceLanguage);
            sourceLanguage.setQName("source-language");
            sourceLanguage.setValue(argXliff.getSourceLanguage());
            // TODO fileの内容調整。

            final BlancoXmlAttribute targetLanguage = new BlancoXmlAttribute();
            eleFile.getAtts().add(targetLanguage);
            targetLanguage.setQName("target-language");
            targetLanguage.setValue(argXliff.getTargetLanguage());
            // TODO fileの内容調整。

            final BlancoXmlAttribute dataType = new BlancoXmlAttribute();
            eleFile.getAtts().add(dataType);
            dataType.setQName("datatype");
            dataType.setValue("PROPERTIES");
            // TODO fileの内容調整。
        }

        eleFile.getChildNodes().add(charNewLineWithIndent4);

        final BlancoXmlElement eleHeader = new BlancoXmlElement();
        eleFile.getChildNodes().add(eleHeader);
        eleHeader.setQName("header");

        for (int indexTool = 0; indexTool < argXliff.getToolList().size(); indexTool++) {
            final BlancoXliffTool tool = (BlancoXliffTool) argXliff
                    .getToolList().get(indexTool);

            final BlancoXmlElement eleTool = new BlancoXmlElement();
            eleHeader.getChildNodes().add(charNewLineWithIndent6);
            eleHeader.getChildNodes().add(eleTool);
            eleTool.setQName("tool");

            {
                final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                eleTool.getAtts().add(attr);
                attr.setQName("tool-id");
                attr.setValue(tool.getToolId());
            }
            {
                final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                eleTool.getAtts().add(attr);
                attr.setQName("tool-name");
                attr.setValue(tool.getToolName());
            }
        }

        eleHeader.getChildNodes().add(charNewLineWithIndent4);
        eleFile.getChildNodes().add(charNewLineWithIndent4);

        final BlancoXmlElement eleBody = new BlancoXmlElement();
        eleFile.getChildNodes().add(eleBody);
        eleBody.setQName("body");

        for (int index = 0; index < argXliff.getTransUnitList().size(); index++) {
            final BlancoXliffTransUnit transUnit = (BlancoXliffTransUnit) argXliff
                    .getTransUnitList().get(index);

            eleBody.getChildNodes().add(charNewLineWithIndent6);

            final BlancoXmlElement eleTranUnit = new BlancoXmlElement();
            eleBody.getChildNodes().add(eleTranUnit);
            eleTranUnit.setQName("trans-unit");

            eleTranUnit.getChildNodes().add(charNewLineWithIndent8);

            {
                final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                eleTranUnit.getAtts().add(attr);
                attr.setQName("id");
                attr.setValue(transUnit.getId());
            }

            if (transUnit.getTranslate() == false) {
                // falseの場合にのみセット。trueの場合には何もしません。
                final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                eleTranUnit.getAtts().add(attr);
                attr.setQName("translate");
                attr.setValue("no");
            }

            final BlancoXmlElement eleSource = new BlancoXmlElement();
            eleSource.setQName("source");
            eleTranUnit.getChildNodes().add(eleSource);

            {
                final BlancoXmlCharacters xmlString = new BlancoXmlCharacters();
                xmlString.setValue(transUnit.getSource());
                eleSource.getChildNodes().add(xmlString);
            }

            final BlancoXliffTarget transUnitTarget = (BlancoXliffTarget) transUnit
                    .getTarget();
            if (transUnitTarget != null) {
                eleTranUnit.getChildNodes().add(charNewLineWithIndent8);

                final BlancoXmlElement eleTarget = new BlancoXmlElement();
                eleTarget.setQName("target");
                eleTranUnit.getChildNodes().add(eleTarget);

                if (BlancoStringUtil.null2Blank(transUnitTarget.getState())
                        .length() > 0) {
                    final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                    eleTarget.getAtts().add(attr);
                    attr.setQName("state");
                    attr.setValue(transUnitTarget.getState());
                }

                if (BlancoStringUtil.null2Blank(transUnitTarget.getLang())
                        .length() > 0) {
                    final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                    eleTarget.getAtts().add(attr);
                    attr.setQName("xml:lang");
                    attr.setValue(transUnitTarget.getLang());
                }

                {
                    final BlancoXmlCharacters xmlString = new BlancoXmlCharacters();
                    xmlString.setValue(transUnitTarget.getTarget());
                    eleTarget.getChildNodes().add(xmlString);
                }
            }

            for (int indexNote = 0; indexNote < transUnit.getNoteList().size(); indexNote++) {
                final BlancoXliffNote note = (BlancoXliffNote) transUnit
                        .getNoteList().get(indexNote);
                eleTranUnit.getChildNodes().add(charNewLineWithIndent8);
                expandNote(note, eleTranUnit);
            }

            for (int indexAltTrans = 0; indexAltTrans < transUnit
                    .getAltTransList().size(); indexAltTrans++) {
                final BlancoXliffAltTrans altTrans = (BlancoXliffAltTrans) transUnit
                        .getAltTransList().get(indexAltTrans);

                eleTranUnit.getChildNodes().add(charNewLineWithIndent8);

                final BlancoXmlElement eleAltTrans = new BlancoXmlElement();
                eleAltTrans.setQName("alt-trans");
                eleTranUnit.getChildNodes().add(eleAltTrans);

                if (BlancoStringUtil.null2Blank(altTrans.getToolId()).length() > 0) {
                    final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                    eleAltTrans.getAtts().add(attr);
                    attr.setQName("tool-id");
                    attr.setValue(altTrans.getToolId());
                }

                final BlancoXmlElement eleSourceAltTrans = new BlancoXmlElement();
                eleSourceAltTrans.setQName("source");

                {
                    final BlancoXmlCharacters xmlString = new BlancoXmlCharacters();
                    xmlString.setValue(altTrans.getSource());
                    eleSourceAltTrans.getChildNodes().add(xmlString);
                }

                eleAltTrans.getChildNodes().add(charNewLineWithIndent10);
                eleAltTrans.getChildNodes().add(eleSourceAltTrans);

                final BlancoXmlElement eleTarget = new BlancoXmlElement();
                eleTarget.setQName("target");
                eleAltTrans.getChildNodes().add(charNewLineWithIndent10);
                eleAltTrans.getChildNodes().add(eleTarget);

                if (BlancoStringUtil.null2Blank(altTrans.getLang()).length() > 0) {
                    final BlancoXmlAttribute attr = new BlancoXmlAttribute();
                    eleTarget.getAtts().add(attr);
                    attr.setQName("xml:lang");
                    attr.setValue(altTrans.getLang());
                }

                {
                    final BlancoXmlCharacters xmlString = new BlancoXmlCharacters();
                    xmlString.setValue(altTrans.getTarget().getTarget());
                    eleTarget.getChildNodes().add(xmlString);
                }

                for (int indexNote = 0; indexNote < altTrans.getNoteList()
                        .size(); indexNote++) {
                    final BlancoXliffNote note = (BlancoXliffNote) altTrans
                            .getNoteList().get(indexNote);
                    eleAltTrans.getChildNodes().add(charNewLineWithIndent10);
                    expandNote(note, eleAltTrans);
                }

                eleAltTrans.getChildNodes().add(charNewLineWithIndent8);
            }

            eleTranUnit.getChildNodes().add(charNewLineWithIndent6);
        }

        eleBody.getChildNodes().add(charNewLineWithIndent4);
        eleFile.getChildNodes().add(charNewLineWithIndent2);
        eleXliff.getChildNodes().add(charNewLineWithIndent0);

        return document;
    }

    private void expandNote(final BlancoXliffNote note,
            final BlancoXmlElement targetElement) {
        final BlancoXmlCharacters charNewLineWithIndent8 = new BlancoXmlCharacters();

        final BlancoXmlElement eleNote = new BlancoXmlElement();
        targetElement.getChildNodes().add(charNewLineWithIndent8);
        targetElement.getChildNodes().add(eleNote);
        eleNote.setQName("note");

        if (BlancoStringUtil.null2Blank(note.getLang()).length() > 0) {
            final BlancoXmlAttribute attr = new BlancoXmlAttribute();
            eleNote.getAtts().add(attr);
            attr.setQName("xml:lang");
            attr.setValue(note.getLang());
        }
        if (BlancoStringUtil.null2Blank(note.getFrom()).length() > 0) {
            final BlancoXmlAttribute attr = new BlancoXmlAttribute();
            eleNote.getAtts().add(attr);
            attr.setQName("from");
            attr.setValue(note.getFrom());
        }

        {
            final BlancoXmlCharacters xmlString = new BlancoXmlCharacters();
            xmlString.setValue(note.getText());
            eleNote.getChildNodes().add(xmlString);
        }
    }
}
