/* 
 * $Id: GLSDDocumentModuleChecker.cpp,v 1.8 2006/06/27 13:11:40 ozawa Exp $
 *
 * Copyright 2005- ONGS Inc. All rights reserved.
 * 
 * author: Masanori OZAWA (ozawa@ongs.co.jp)
 * version: $Revision: 1.8 $
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the ONGS Inc.
 * 
 */

#include "xdtp.h"
#include "modules/GLSDDocumentModuleChecker.h"
#include "XMLTool.h"

using namespace XDTP;

GLSDDocumentModuleChecker::GLSDDocumentModuleChecker()
{
}

GLSDDocumentModuleChecker::~GLSDDocumentModuleChecker()
{
}

/**
 * 文書モジュールの正当性をチェックします。
 * 
 * @param aDocument ロードした直後のXMLファイル
 * @return 変換処理を中断する場合は false を戻します。
 */
bool GLSDDocumentModuleChecker::checkFormat(xmlDocPtr aDocument)
{
    bool result = true;
    int count = 0;
    int count2 = 0;
    int count3 = 0;

    XMLTool tool;
    xmlNodePtr node;
    xmlNodePtr child;
    xmlNodePtr root = xmlDocGetRootElement(aDocument);
    xmlXPathObjectPtr obj;
    xmlXPathObjectPtr children;
    xmlXPathObjectPtr tmpobj;
    xmlXPathObjectPtr tmpobj2;
    xmlNodeSetPtr nodes;
    xmlNodeSetPtr childset;
    xmlNodeSetPtr tmpobjset;
    
    // alias のチェック
    if (!checkAlias(root)) {
        return false;
    }

    // import のチェック
    obj = tool.getNodeList(root, "//import");
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
            if (!tool.isElement(nodes->nodeTab[count])) continue;
            if (!xmlHasProp(nodes->nodeTab[count], (const xmlChar*)"type") ||
                !xmlHasProp(nodes->nodeTab[count], (const xmlChar*)"ref"))
            {
                result = false;
            }
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad import." LINE_SEP, APP_NAME);
    }

    // mark のチェック
    obj = (result ? tool.getNodeList(root, "//mark") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
            if (!tool.isElement(nodes->nodeTab[count])) continue;
            if (!xmlHasProp(nodes->nodeTab[count], (const xmlChar*)"type")) {
                result = false;
            }
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad mark." LINE_SEP, APP_NAME);
    }

    // list のチェック
    obj = (result ? tool.getNodeList(root, "//list") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
        	node = nodes->nodeTab[count];
		    if (!tool.isElement(node)) continue;
        	result = checkFormat_list(node);
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad list." LINE_SEP, APP_NAME);
    }

   // thebibliography のチェック
    obj = (result ? tool.getNodeList(root, "//thebibliography") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
            node = nodes->nodeTab[count];
            if (!tool.isElement(node)) continue;

            children = tool.getNodeList(node, "./bibitem");
            if (!children) {
                result = false;
            }
            else {
                childset = children->nodesetval;
                if (1 > childset->nodeNr) result = false;
                
                for (count2 = 0; result && count2 < childset->nodeNr; count2++) {
                    child = childset->nodeTab[count2];
                    
                    tmpobj = tool.getNodeList(child, "./title");
                    if (!tmpobj) result = false;
                    else {
                        if (0 >= tmpobj->nodesetval->nodeNr) result = false;
                        xmlXPathFreeObject(tmpobj);
                    }

                    tmpobj = tool.getNodeList(child, "./publisher");
                    if (tmpobj) {
                        if (1 < tmpobj->nodesetval->nodeNr) result = false;
                        xmlXPathFreeObject(tmpobj);
                    }

                    tmpobj = tool.getNodeList(child, "author | title | publisher | year");
                    if (tmpobj) {
                        tmpobjset = tmpobj->nodesetval;
                        
                        for (count3 = 0; result && count3 < tmpobjset->nodeNr; count3++) {
                            tmpobj2 = tool.getNodeList(tmpobjset->nodeTab[count3], "./p");
                            if (!tmpobj2) result = false;
                            else {
                                if (1 != tmpobj2->nodesetval->nodeNr) result = false;
                                xmlXPathFreeObject(tmpobj2);
                            }
                        }
                        
                        xmlXPathFreeObject(tmpobj);
                    }
                }
                
                xmlXPathFreeObject(children);
            }
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad thebibliography." LINE_SEP, APP_NAME);
    }

    // footnote のチェック
    obj = (result ? tool.getNodeList(root, "//footnote") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; count < nodes->nodeNr; count++) {
            if (!tool.isElement(nodes->nodeTab[count])) continue;

            children = tool.getNodeList(nodes->nodeTab[count], "./*");
            if (children) {
                if (0 != children->nodesetval->nodeNr) result = false;
                xmlXPathFreeObject(children);
            }
        }
        
        xmlXPathFreeObject(obj);
        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad footnote." LINE_SEP, APP_NAME);
    }

    // access のチェック
    obj = (result ? tool.getNodeList(root, "//access") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
            node = nodes->nodeTab[count];
            if (!tool.isElement(node)) continue;
            if (!xmlHasProp(node, (const xmlChar*)"ref")) {
                result = false;
            }
            
            children = (result ? tool.getNodeList(node, "./*") : NULL);
            if (children) {
                if (0 != children->nodesetval->nodeNr) result = false;
                xmlXPathFreeObject(children);
            }
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad access." LINE_SEP, APP_NAME);
    }

    // ruby のチェック
    obj = (result ? tool.getNodeList(root, "//ruby") : NULL);
    
    if (obj) {
        nodes = obj->nodesetval;
        for (count = 0; result && count < nodes->nodeNr; count++) {
            node = nodes->nodeTab[count];
            if (!tool.isElement(node)) continue;
            if (!xmlHasProp(node, (const xmlChar*)"rubytext")) {
                result = false;
            }
            
            children = tool.getNodeList(node, "./*");
            if (children) {
                if (0 != children->nodesetval->nodeNr) result = false;
                xmlXPathFreeObject(children);
            }
        }
        
        xmlXPathFreeObject(obj);

        if (!result) fprintf(stderr, "%s: GLSDDocumentModuleChecker: bad ruby." LINE_SEP, APP_NAME);
    }

    return result;
}

/**
 * aliasエレメントの確認。
 * 
 * @param aDocumentRoot
 *            XMLのルートノード
 */
bool GLSDDocumentModuleChecker::checkAlias(xmlNodePtr aDocumentRoot)
{
    bool result = true;
    int count;

    XMLTool tool;
    xmlNodePtr node;
    xmlNodePtr child;
    xmlNodeSetPtr nodes;
    xmlXPathObjectPtr obj = tool.getNodeList(aDocumentRoot, "//alias");

    if (obj) {
        nodes = obj->nodesetval;

        for (count = 0; result && count < nodes->nodeNr; count++) {
            node = nodes->nodeTab[count];
            
            if (!node->parent || xmlStrcmp(node->parent->name, (xmlChar*)"p") != 0)
                result = false;
            else {
                for (child = node->children; result && child; child = child->next) {
                    if (!tool.isText(child)) result = false;
                }
                if (result) {
                    if (0 >= tool.getText(node).length()) result = false;
                }
            }
        }

        xmlXPathFreeObject(obj);
    }
    
    return result;
}

/**
 * list要素の構造をチェックします。
 * 
 * @param aNode 親list要素
 * @return 変換処理を中断する場合は false を戻します。
 */
bool GLSDDocumentModuleChecker::checkFormat_list(xmlNodePtr aNode)
{
	bool result = true;
	int count, count2;
    XMLTool tool;
    xmlNodePtr node;
    xmlNodePtr child;
    xmlXPathObjectPtr children;
    xmlXPathObjectPtr tmpobj;
    xmlNodeSetPtr childset;
    xmlNodeSetPtr tmpobjset;

    children = tool.getNodeList(aNode, "./item");
    if (children) {
        childset = children->nodesetval;
        
        for (count = 0; result && count < childset->nodeNr; count++) {
            child = childset->nodeTab[count];
            
            // 最低1つのp要素が必要
            tmpobj = tool.getNodeList(child, "./p");
            
            if (!tmpobj) result = false;
            else {
                if (0 >= tmpobj->nodesetval->nodeNr) result = false;
                
                xmlXPathFreeObject(tmpobj);
            }
            
            // ネストされたlist要素をチェック
		    tmpobj = tool.getNodeList(child, "./list");
		    if (tmpobj) {
		    	tmpobjset = tmpobj->nodesetval;
		    	
		    	for (count2 = 0; result && count2 < tmpobjset->nodeNr; count2++) {
		        	node = tmpobjset->nodeTab[count2];
				    if (!tool.isElement(node)) continue;
		        	result = checkFormat_list(node);
		    	}

		        xmlXPathFreeObject(tmpobj);
		    }
        }
        
        xmlXPathFreeObject(children);
    }
    
    return result;
}


syntax highlighted by Code2HTML, v. 0.9.1