package org.itscool.commons.document;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * JSONとはJavaScript Object
 * Notationの略称です。このJSON形式のデータはJavaScriptで式評価が許される
 * （eval()で式評価できる）ものであれば何でも構いません。
 * 基本的には以下の形式になります。
 *
 *  { "プロパティ名" : 値 }
 *
 * このデータを読み込み利用するにはdata = eval("("+データ+")")とすると変数dataに
 * JSONで定義されたプロパティの値が入ります。
 * 例えば以下のようなJSONファイルがあるとします。
 *
 * {
 * "userID":"ajax",
 * "userPW":"xanadu"
 * }
 *
 *
 * このデータを変数dataに読み込んだとします。userIDプロパティの値を読み出すには
 * data.userIDと記述します。
 * するとajaxの文字が返されます。同様にdata.userPWとするとxanaduの文字が返されま
 * す。単純にオブジェクト名.プロパティ名の記述で済みます。
 * プロパティの値には関数なども定義することができます。
 * これによりオブジェクト名.プロパティ名()として末尾にカッコを付加した場合にプロ
 * パティの内容＝関数が実行されます。
 * つまりメソッドを定義したのと同じことになります。
 *
 * それでは実際のデータを読み込み表示してみます。以下の商品名とそれに関するデータ
 * が記述されたJSONデータを読み込み表示します
 * JSONデータは単純なテキストファイルなのでresponseTextで取得する必要があります。
 * 取得したデータをeval()で評価し、各プロパティを表示すればできあがりです。
 * 実際には商品名が１つということはありません。かなり多くの商品リストがあり、項
 * 目も多岐に渡るはずです。
 * このような場合には配列を利用してJSONデータとして定義します。
 * これは以下のようになります。
 *
 * ●複数のデータを含むJSONデータ
 *
 * {"item":[
 * {"itemCode":91,
 * "itemName":"塩ラーメン",
 * "itemPrice":300},
 *
 * {"itemCode":94,
 * "itemName":"味噌ラーメン",
 * "itemPrice":290},
 *
 * {"itemCode":95,
 * "itemName":"豚骨ラーメン",
 * "itemPrice":320}
 * ]
 * }
 *
 * この場合、変数dataにデータが読み込まれた場合、最初のデータ（塩ラーメン）に
 * アクセスするにはdata.item[0].itemCodeのようにします。
 * 配列として定義されているので、このように記述することになります。
 * 2番目のデータであればdata.item[1].itemCodeとなります。
 * あとは必要に応じてデータの数だけ繰り返せばよいことになります。
 * 上記のデータを表示するプログラムは以下のようになります。
 * （実際のサンプルを実行する）
 *
 *
 * @version 1.00A 2006/08/23 新規作成
 * @author kano
 *
 */
public class BeanToJsonDocument extends AbstractDocument{
    private String LINE=System.getProperty("line.separator");
    private ArrayList pBeanList = new ArrayList();
    private String rootName;
    
    /**
     * ルート名「rootName」で指定した新しいDocumentインスタンスを
     * 作成します
     * @param rootName このドキュメントのルート要素の名前
     * @throws Exception
     */
    public BeanToJsonDocument(String rootName) {
        this.rootName = rootName;
    }
    
    /**
     * 指定されたオブジェクトをドキュメントに追加します<BR>
     * 要素名はオブジェクトのクラス名がセットされます
     * @param bean ドキュメントに追加するオブジェクト
     * @throws Exception
     */
    public void addElement(Object bean) throws Exception{
        DocumentBean pBean = DocumentBeanParser.parseBean(bean, bean.getClass(), this);
        addElement(pBean);
    }
    
    /**
     * Listインスタンスに登録されているオブジェクトをドキュメントに
     * 追加します<BR>
     * @param list ドキュメントに追加するListインスタンス
     * @throws Exception
     */
    public void addElement(List list) throws Exception{
        for( int i=0; i<list.size(); i++){
            Object bean = list.get(i);
            DocumentBean pBean = DocumentBeanParser.parseBean(bean, bean.getClass(), this);
            addElement(pBean);
        }
    }
    
    /**
     * Mapインスタンスに登録されているオブジェクトをドキュメントに
     * 追加します<BR>
     * @param map ドキュメントに追加するMapインスタンス
     * @throws Exception
     */
    public void addElement(Map map) throws Exception{
        Set set = map.keySet();
        Iterator it = set.iterator();
        while( it.hasNext()){
            Object key = it.next();
            Object bean = map.get(key);
            DocumentBean pBean = DocumentBeanParser.parseBean(bean, bean.getClass(), this);
            addElement(pBean);
        }
    }
    
    /**
     * JavaBeans展開オブジェクトをドキュメントに追加します
     * @param pBean ドキュメントに追加するParseBeanインスタンス
     * @throws Exception
     */
    protected void addElement(DocumentBean pBean) throws Exception{
        pBeanList.add(pBean);
    }
    
    /**
     * DocumentBeanインスタンスからJSONフォーマットを生成します
     * @return JSON形式のテキスト
     */
    public String parseText(){
        StringBuffer sb = new StringBuffer("{\""+rootName+"\":");
        //sb.append(LINE);
        int size = pBeanList.size();
        for(int i=0; i<size; i++){
            DocumentBean dBean = (DocumentBean)pBeanList.get(i);
            sb.append("{");
            int dBeanSize = dBean.size();
            if( dBeanSize > 1 ){
                for(int j=0; j<dBeanSize; j++){

                    DocumentBean child = (DocumentBean)dBean.get(j);
                    String value = parseText(child, child.getName());
                    sb.append(value);

                    if((j+1)<dBeanSize){
                        sb.append(",");
                        //sb.append(LINE);
                    }
                }
            }else{
                String name = dBean.getName();
                String value = (String)dBean.getValue();
                sb.append("\""+name+"\":");
                sb.append("\""+value+"\"");
            }
            sb.append("}");
            if( (i+1)<size ){
                sb.append(",");
                //sb.append(LINE);
            }
            //sb.append(LINE);
        }
        sb.append("}");
        return sb.toString();
    }
    
    /**
     * 子DocumentBeanインスタンスからJSONフォーマットを生成します
     * @param dBean 子DocumentBean
     * @param parentName 親の名前
     * @return JSON形式のテキスト
     */
    public String parseText(DocumentBean dBean, String parentName){
        StringBuffer sb = new StringBuffer();
        sb.append("\""+parentName+"\":");
        
        //sb.append(LINE);
        int size = pBeanList.size();
        
        int dBeanSize = dBean.size();
        if( dBeanSize > 1 ){
            sb.append("{");
            for(int j=0; j<dBeanSize; j++){
                DocumentBean child = (DocumentBean)dBean.get(j);
                String value = parseText(child, child.getName());
                sb.append(value);

                if(j<(dBeanSize-1)){
                    sb.append(",");
                    //sb.append(LINE);
                }
            }
            sb.append("}");
        }else{
            sb.append("\"").append(dBean.getValue()).append("\"");
        }
        
        
        //sb.append(LINE);
        
        return sb.toString();
    }
}



