package org.itscool.weber.io;

import java.io.IOException;
import java.util.HashMap;

import org.itscool.commons.document.XmlConfigReader;
import org.itscool.weber.mapping.ActionMapping;
import org.itscool.weber.mapping.ValidationMapping;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * weber-config.xmlの&lt;action-mappings&gt;要素を解析するクラスです
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 */
public class ActionConfigReader extends XmlConfigReader{
    /**
     * XMLファイルから&lt;action-mappings&gt;要素を解析します<br>
     * 解析結果はhashMapにセットします<br>
     * @param hashMap XMLの解析結果
    */
    protected void doCreate(HashMap hashMap) throws IOException{
        
        /* ルートタグ名を取得 */
        Element root = document.getDocumentElement();
        if( root == null ){
            String err = "Can not root element at itscool-config.xml(" + 
                getClass().getName()+")";
            throw new IOException(err);
        }
        
        /* action-mappings の取得*/
        NodeList mappingsList = root.getElementsByTagName("action-mappings");
        if( mappingsList == null ){
            String err = "Can not element at <action-maggpins>(" + 
                getClass().getName()+")";
            throw new IOException(err);
        }
        
        Node mappings = mappingsList.item(0);
        if( mappings != null ){
            createMappings(mappings, hashMap);
        }
    }
    
    /**
     * &lt;action-mappings&gt;要素を解析します
     * @param mappings &lt;action-mappings&gt;要素
     * @param hashMap 解析後の&lt;action&gt;情報を追加するノードリスト
     * @throws Exception
     */
    protected void createMappings(Node mappings, HashMap hashMap)
    throws IOException{
        NodeList mappingsChilds = mappings.getChildNodes();
        
        for( int i = 0; i < mappingsChilds.getLength(); i++) {
            Node action = mappingsChilds.item(i);
            if( action.getNodeName().equals("action")){
                createAction(action, hashMap);
            }
        }
    }
    
    /**
     * &lt;action-mappings&gt;要素の属性と子要素を解析します
     * @param action &lt;action&gt;要素
     * @param hashMap 解析後の&lt;action&gt;情報を追加するノードリスト
     * @throws Exception
     */
    protected void createAction(Node action, HashMap hashMap)
    throws IOException{
        NamedNodeMap attributes = action.getAttributes();
        Node path = attributes.getNamedItem("path");
        Node type = attributes.getNamedItem("type");
        Node name = attributes.getNamedItem("name");
        
        if( path == null || path.getNodeName().length() == 0){
        	throw new IOException("action tag's path is null");
        }
        if( type == null || type.getNodeName().length() == 0){
        	throw new IOException("action tag's type is null");
        }
        String nameStr = null;
        if(name != null){
            nameStr = name.getNodeValue();
        }
        
        ActionMapping actionMapping = 
            new ActionMapping(path.getNodeValue(), 
                    type.getNodeValue(), nameStr);
        
        NodeList childs = action.getChildNodes();
        for( int i=0; i<childs.getLength(); i++){
            Node child = childs.item(i);
            if( child.getNodeName().equals("forward")){
                createForward(child, actionMapping);
            }else if( child.getNodeName().equals("role")){
                createRole(child, actionMapping);
            }else if( child.getNodeName().equals("param")){
            	createParam(child, actionMapping);
            }
        }
        
        hashMap.put( actionMapping.getPath(), (Object)actionMapping );
    }
    
    /**
     * &lt;action&gt;要素の子要素（&lt;forward&gt;）を解析します
     * @param forward &lt;forward&gt;要素
     * @param actionMapping 解析後の&lt;forward&gt;情報を追加する
     *              ActionMappingインスタンス
     * @throws Exception
     */
    protected void createForward(Node forward, ActionMapping actionMapping)
    throws IOException{
        NamedNodeMap attributes = forward.getAttributes();
        Node path = attributes.getNamedItem("path");
        Node name = attributes.getNamedItem("name");
        if( path == null || path.getNodeName().length() == 0){
        	throw new IOException("forward tag's path is null.");
        }
        if( name == null || name.getNodeName().length() == 0){
			throw new IOException("forward tag's name is null.");
		}
        
        actionMapping.addForward(name.getNodeValue(), path.getNodeValue());
    }
    
    /**
     * &lt;action&gt;要素の子要素（&lt;role&gt;）を解析します
     * @param role &lt;role&gt;要素(権限)
     * @param actionMapping 解析後の&lt;role&gt;情報を追加する
     *              ActionMappingインスタンス
     * @throws Exception
     */
    protected void createRole(Node role, ActionMapping actionMapping)
    throws IOException{
        NamedNodeMap attributes = role.getAttributes();
        Node name = attributes.getNamedItem("name");
        
        if( name == null || name.getNodeName().length() == 0){
			throw new IOException("role tag's name is null.");
        }
        //RoleFileDefines roleMappings = RoleFileDefines.getInstance();
        //UserRole userRole = (UserRole)roleMappings.get(name.getNodeValue());
        //UserRole userRole = new UserRole();
        //userRole.setName(name.getNodeValue());
        String roleName = name.getNodeValue();
        actionMapping.addRole(roleName);
    }
    
    /**
     * &lt;action&gt;要素の子要素（&lt;param&gt;）を解析します
     * @param param &lt;param&gt;要素(パラメータ名)
     * @param actionMapping 解析後の&lt;param&gt;情報を追加する
     *              ActionMappingインスタンス
     * @throws Exception
     */
    protected void createParam(Node param, ActionMapping actionMapping)
    throws IOException{
        NamedNodeMap attributes = param.getAttributes();
        Node name = attributes.getNamedItem("name");
        
        if( name == null || name.getNodeName().length() == 0){
			throw new IOException("param tag's name is null.");
        }
        //RoleFileDefines roleMappings = RoleFileDefines.getInstance();
        //UserRole userRole = (UserRole)roleMappings.get(name.getNodeValue());
        //UserRole userRole = new UserRole();
        //userRole.setName(name.getNodeValue());
        String paramName = name.getNodeValue();
        NodeList childs = param.getChildNodes();
        for( int i=0; i<childs.getLength(); i++){
            Node child = childs.item(i);
            if( child.getNodeName().equals("validate")){
            	ValidationMapping validate = createValidate(paramName, child);
            	actionMapping.addValidate(validate);
            }
        }
    }
    
    protected ValidationMapping createValidate(String paramName, Node validate)
    throws IOException{
        NamedNodeMap attributes = validate.getAttributes();
        Node type = attributes.getNamedItem("type");
        Node msgkey = attributes.getNamedItem("msgkey");
        Node msgbody = attributes.getNamedItem("msgbody");
        Node min = attributes.getNamedItem("min");
        Node max = attributes.getNamedItem("max");
        Node length = attributes.getNamedItem("length");
        
        if( type == null || type.getNodeName().length() == 0){
			throw new IOException("validate param tag's type is null.");
        }
        ValidationMapping validationMapping = new ValidationMapping();
        validationMapping.setParamName(paramName);
        validationMapping.setType(type.getNodeValue());
        if(msgbody==null && msgkey==null){
        	throw new IOException("validate param tag's msgbody and msgkey is null.");
        }
        if(msgbody != null){
        	validationMapping.setMsgbody(msgbody.getNodeValue());
        }
        if(msgkey != null){
        	validationMapping.setMsgkey(msgkey.getNodeValue());
        }
        if(min != null){
        	try{
        		validationMapping.setMin(Double.parseDouble(min.getNodeValue()));
        	}catch(NumberFormatException e){
        		throw new IOException(e.getMessage());
        	}
        }
        if(max != null){
        	try{
        		validationMapping.setMax(Double.parseDouble(max.getNodeValue()));
        	}catch(NumberFormatException e){
        		throw new IOException(e.getMessage());
        	}
        }
        if(length != null){
        	try{
        		validationMapping.setLength(Integer.parseInt(length.getNodeValue()));
        	}catch(NumberFormatException e){
        		throw new IOException(e.getMessage());
        	}
        }
        return validationMapping;
    }
}
