    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.hayabusa.html;
    017
    018import org.opengion.fukurou.util.StringUtil ;
    019
    020import java.util.Map;
    021import java.util.HashMap;
    022import java.util.List;
    023import java.util.ArrayList;
    024import java.util.Arrays;
    025
    026/**
    027 * String[] 型キーにカラム列の連想記憶を用いた、クロス集計データを管理するクラスです。
    028 *
    029 * クロス集計では、カラム列が、データとして与えられる為、このクラス内部で、
    030 * 一旦カラム列の連想記憶(Map)データを作成し、実際の行データ登録時にデータを
    031 * 設定しています。
    032 * 取り出すときは、一気に取り出すことを考慮して、配列(ArrayList)データに
    033 * 共有しているオブジェクトを取り出します。
    034 *
    035 * この実装は同期化されません。
    036 *
    037 * @og.rev 3.5.4.0 (2003/11/25) 新規作成
    038 * @og.group 画面表示
    039 *
    040 * @version  4.0
    041 * @author   Kazuhiko Hasegawa
    042 * @since    JDK5.0,
    043 */
    044public final class CrossMap {
    045        private final Map<String,String[]> row = new HashMap<String,String[]>() ;
    046        private final Map<String,Integer>  clm = new HashMap<String,Integer>() ;
    047        private final List<String[]> list = new ArrayList<String[]>();
    048        private final int headCount;
    049        private final int sumCount;
    050        private final int totalCols;
    051
    052        /**
    053         * カラム部(クロス集計部)を与えて新しく作成するコンストラクター
    054         *
    055         * クロス集計を行うカラム部のみセットします。
    056         * 行のクロス集計部のヘッダーキーは、引数の配列の順番で、設定されます。
    057         * この行のヘッダー部となるデータは、addData 時にセットします。
    058         *
    059         * @param       clmData         クロス集計部のカラム名配列
    060         * @param       headCount       HEADカラムの数
    061         * @param       sumCount        合計カラムの数
    062         */
    063        public CrossMap( final String[] clmData, final int headCount, final int sumCount ) {
    064                if( headCount <= 0 ) {
    065                        String errMsg = "headCount は、ROWカラムを含むため、最低１以上必要です。";
    066                        throw new IllegalArgumentException( errMsg );
    067                }
    068
    069                this.headCount = headCount;
    070                this.sumCount  = sumCount;
    071                int clmNum = clmData.length;
    072                totalCols = headCount + clmNum * sumCount;
    073                for( int i=0; i<clmNum; i++ ) {
    074                        clm.put( clmData[i],Integer.valueOf( i ) );
    075                }
    076        }
    077
    078        /**
    079         * クロス集計の元となる検索結果の行データを登録します。
    080         *
    081         * クロス集計を行うカラム部のみ,セットします。
    082         * 行のヘッダー部となるデータは、rowKeys と headCount で指定します。
    083         * 行のクロス集計部のヘッダーキーは、clmKey で指定し、内部で、列カラムとして
    084         * 割り当てられます。割り当て順(カラム順)は、コンストラクタでの clmData の
    085         * 配列の順番です。
    086         *
    087         * @param       rowKeys 行データの配列( ０〜headCount の値が行のキーとなります。)
    088         */
    089        public void add( final String[] rowKeys ) {
    090                if( rowKeys.length < headCount + 1 + sumCount) {
    091                        String errMsg = "指定の rowKeys の個数が不正です。 rowKeys には、clmKey と data が必要です。"
    092                                                + " rowKeys=" + StringUtil.array2csv( rowKeys ) ;       // 5.1.8.0 (2010/07/01) errMsg 修正
    093                        throw new ArrayIndexOutOfBoundsException( errMsg );
    094                }
    095
    096                // 3.5.6.6 (2004/08/23) 修正
    097                String clmKey = rowKeys[headCount];                             // カラム列のクロス集計部のキー(ヘッダー)
    098                String[] data = new String[sumCount];   // クロス集計表の値
    099                for( int i=0; i<sumCount; i++ ) {
    100                        data[i] = rowKeys[headCount+1+i];
    101                }
    102
    103                String rowKey ;
    104                // 3.5.6.6 (2004/08/23) 修正
    105                if( headCount == 1 ) { rowKey = rowKeys[0]; }
    106                else {
    107                        StringBuilder rKey = new StringBuilder();
    108                        for( int i=0; i<headCount; i++ ) {
    109                                rKey.append( rowKeys[i] );
    110                                rKey.append( "_" );
    111                        }
    112                        rowKey = rKey.toString();
    113                }
    114                String[] clmData = row.get( rowKey );
    115                if( clmData == null ) {
    116                        // 行データ+クロス行データ
    117                        clmData = new String[totalCols];
    118                        Arrays.fill( clmData,"" );
    119                        for( int i=0; i<headCount; i++ ) {
    120                                clmData[i] = rowKeys[i];
    121                        }
    122                        list.add( clmData );    // 生成順にArrayList にセーブします。
    123                }
    124
    125                for( int i=0; i<sumCount; i++ ) {
    126                        int no = headCount + (clm.get( clmKey )).intValue()*sumCount+i; // 列番号
    127                        clmData[no] = data[i];
    128                }
    129                row.put( rowKey,clmData );      // ArrayList と同じオブジェクトを検索用のMapにもセットする。
    130        }
    131
    132        /**
    133         * クロス集計結果の指定行の列データを返します。
    134         *
    135         * @param       row 指定の行番号( 0 .. getSize()-1 )
    136         *
    137         * @return      列データ配列
    138         */
    139        public String[] get( final int row ) {
    140                return list.get( row );
    141        }
    142
    143        /**
    144         * クロス集計結果の行数を返します。
    145         *
    146         * @return   行数を返します。
    147         */
    148        public int getSize() {
    149                return list.size();
    150        }
    151}