/*******************************************************************************
 * 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.util.List;

import blanco.commons.util.BlancoStringUtil;
import blanco.xliff.valueobject.BlancoXliff;
import blanco.xliff.valueobject.BlancoXliffAltTrans;
import blanco.xliff.valueobject.BlancoXliffFile;
import blanco.xliff.valueobject.BlancoXliffNote;
import blanco.xliff.valueobject.BlancoXliffTarget;
import blanco.xliff.valueobject.BlancoXliffTool;
import blanco.xliff.valueobject.BlancoXliffTransUnit;
import blanco.xml.bind.BlancoXmlBindingUtil;
import blanco.xml.bind.BlancoXmlUnmarshaller;
import blanco.xml.bind.valueobject.BlancoXmlDocument;
import blanco.xml.bind.valueobject.BlancoXmlElement;

/**
 * OASIS XLIFF をパースするクラス。
 * 
 * @author IGA Tosiki
 */
public class BlancoXliffParser {
    /**
     * 指定されたファイルからXLIFFを読み込みます。
     * 
     * @param argFileTarget
     * @return
     */
    public BlancoXliff parse(final File argFileTarget) {
        final BlancoXmlDocument document = new BlancoXmlUnmarshaller()
                .unmarshal(argFileTarget);
        return document2ValueObject(document);
    }

    /**
     * blancoドキュメントからバリューオブジェクトに変換します。
     * 
     * @param argDocument
     * @return
     */
    public BlancoXliff document2ValueObject(final BlancoXmlDocument argDocument) {
        final BlancoXmlElement eleXliff = (BlancoXmlElement) argDocument
                .getChildNodes().get(0);
        if ("xliff".equals(eleXliff.getLocalName()) == false) {
            throw new IllegalArgumentException("不正なXLIFFが与えられました。("
                    + eleXliff.getLocalName() + ")");
        }

        final BlancoXliff xliff = new BlancoXliff();

        xliff
                .setVersion(BlancoXmlBindingUtil.getAttribute(eleXliff,
                        "version"));

        final List eleFileList = BlancoXmlBindingUtil.getElementsByTagName(
                eleXliff, "file");

        for (int indexFileList = 0; indexFileList < eleFileList.size(); indexFileList++) {
            final BlancoXmlElement eleFile = (BlancoXmlElement) eleFileList
                    .get(indexFileList);
            if (eleFile == null) {
                throw new IllegalArgumentException(
                        "不正なXLIFFが与えられました。file見つけられず");
            }

            final BlancoXliffFile file = new BlancoXliffFile();
            xliff.getFileList().add(file);

            file.setSourceLanguage(BlancoXmlBindingUtil.getAttribute(eleFile,
                    "source-language"));
            file.setTargetLanguage(BlancoXmlBindingUtil.getAttribute(eleFile,
                    "target-language"));
            file.setOriginal(BlancoXmlBindingUtil.getAttribute(eleFile,
                    "original"));
            file.setDatatype(BlancoXmlBindingUtil.getAttribute(eleFile,
                    "datatype"));

            final BlancoXmlElement eleHeader = BlancoXmlBindingUtil.getElement(
                    eleFile, "header");
            if (eleHeader == null) {
                throw new IllegalArgumentException(
                        "不正なXLIFFが与えられました。header見つけられず");
            }
            final BlancoXmlElement eleBody = BlancoXmlBindingUtil.getElement(
                    eleFile, "body");
            if (eleBody == null) {
                throw new IllegalArgumentException(
                        "不正なXLIFFが与えられました。body見つけられず");
            }

            final List toolList = BlancoXmlBindingUtil.getElementsByTagName(
                    eleHeader, "tool");
            for (int indexTool = 0; indexTool < toolList.size(); indexTool++) {
                final BlancoXliffTool tool = new BlancoXliffTool();
                final BlancoXmlElement eleTool = (BlancoXmlElement) toolList
                        .get(indexTool);
                tool.setToolId(BlancoXmlBindingUtil.getAttribute(eleTool,
                        "tool-id"));
                tool.setToolName(BlancoXmlBindingUtil.getAttribute(eleTool,
                        "tool-name"));
                file.getHeader().getToolList().add(tool);
            }

            final List transUnitList = BlancoXmlBindingUtil
                    .getElementsByTagName(eleBody, "trans-unit");
            for (int indexTransUnit = 0; indexTransUnit < transUnitList.size(); indexTransUnit++) {
                final BlancoXmlElement transUnit = (BlancoXmlElement) transUnitList
                        .get(indexTransUnit);
                final BlancoXliffTransUnit eleTransUnit = new BlancoXliffTransUnit();

                // trans-unitのid属性
                eleTransUnit.setId(BlancoXmlBindingUtil.getAttribute(transUnit,
                        "id"));

                // trans-unitのtranslate属性
                eleTransUnit.setTranslate("no".equals(BlancoXmlBindingUtil
                        .getAttribute(transUnit, "translate")) == false);

                // source要素
                eleTransUnit.setSource(BlancoXmlBindingUtil.getTextContent(
                        transUnit, "source"));

                // target要素
                {
                    final BlancoXmlElement target = BlancoXmlBindingUtil
                            .getElement(transUnit, "target");
                    if (target != null) {
                        final BlancoXliffTarget eleTarget = new BlancoXliffTarget();
                        eleTransUnit.setTarget(eleTarget);

                        parseTarget(target, eleTarget);
                    }
                }

                // note要素
                List noteList = BlancoXmlBindingUtil.getElementsByTagName(
                        transUnit, "note");
                for (int indexNoteList = 0; indexNoteList < noteList.size(); indexNoteList++) {
                    final BlancoXmlElement eleNote = (BlancoXmlElement) noteList
                            .get(indexNoteList);
                    final BlancoXliffNote note = new BlancoXliffNote();
                    eleTransUnit.getNoteList().add(note);
                    parseNote(eleNote, note);
                }

                // alt-trans要素
                List altTransList = BlancoXmlBindingUtil.getElementsByTagName(
                        transUnit, "alt-trans");
                for (int indexAltTrans = 0; indexAltTrans < altTransList.size(); indexAltTrans++) {
                    final BlancoXmlElement altTrans = (BlancoXmlElement) altTransList
                            .get(indexAltTrans);
                    final BlancoXliffAltTrans eleAltTrans = new BlancoXliffAltTrans();
                    eleTransUnit.getAltTransList().add(eleAltTrans);

                    // tool-id属性
                    final String toolId = BlancoStringUtil
                            .null2Blank(BlancoXmlBindingUtil.getAttribute(
                                    altTrans, "tool-id"));
                    if (toolId.length() > 0) {
                        eleAltTrans.setToolId(toolId);
                    }

                    // source要素
                    eleAltTrans.setSource(BlancoXmlBindingUtil.getTextContent(
                            altTrans, "source"));

                    // target要素
                    {
                        final BlancoXmlElement target = BlancoXmlBindingUtil
                                .getElement(altTrans, "target");
                        if (target != null) {
                            final BlancoXliffTarget eleTarget = new BlancoXliffTarget();
                            eleAltTrans.setTarget(eleTarget);

                            parseTarget(target, eleTarget);
                        }
                    }

                    // note要素
                    List altTransNoteList = BlancoXmlBindingUtil
                            .getElementsByTagName(altTrans, "note");
                    for (int indexNoteList = 0; indexNoteList < altTransNoteList
                            .size(); indexNoteList++) {
                        final BlancoXmlElement eleNote = (BlancoXmlElement) altTransNoteList
                                .get(indexNoteList);
                        final BlancoXliffNote note = new BlancoXliffNote();
                        eleAltTrans.getNoteList().add(note);
                        parseNote(eleNote, note);
                    }
                }

                file.getBody().getTransUnitList().add(eleTransUnit);
            }
        }
        return xliff;
    }

    /**
     * targetノードをパースします。
     * 
     * @param eleTarget
     * @param target
     */
    private void parseTarget(final BlancoXmlElement eleTarget,
            final BlancoXliffTarget target) {
        // target テキスト。
        target.setTarget(BlancoXmlBindingUtil.getTextContent(eleTarget));

        final String lang = BlancoStringUtil.null2Blank(BlancoXmlBindingUtil
                .getAttribute(eleTarget, "xml:lang"));
        if (lang.length() > 0) {
            target.setLang(lang);
        }

        final String state = BlancoStringUtil.null2Blank(BlancoXmlBindingUtil
                .getAttribute(eleTarget, "state"));
        if (state.length() > 0) {
            target.setState(state);
        }
    }

    private void parseNote(final BlancoXmlElement eleNote,
            final BlancoXliffNote note) {
        // xml-lang属性
        final String lang = BlancoStringUtil.null2Blank(BlancoXmlBindingUtil
                .getAttribute(eleNote, "xml:lang"));
        if (lang.length() > 0) {
            note.setLang(lang);
        }

        // from属性
        final String from = BlancoStringUtil.null2Blank(BlancoXmlBindingUtil
                .getAttribute(eleNote, "from"));
        if (from.length() > 0) {
            note.setFrom(from);
        }

        // note要素テキスト
        note.setText(BlancoXmlBindingUtil.getTextContent(eleNote));
    }
}
