/*
 * This software is distributed under following license based on modified BSD
 * style license.
 * ----------------------------------------------------------------------
 * 
 * Copyright 2009 The Nimbus2 Project. All rights reserved.
 * 
 * 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 THE NIMBUS PROJECT ``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 THE NIMBUS PROJECT 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 Nimbus2 Project.
 */
package jp.ossc.nimbus.util.converter;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.lang.IllegalArgumentException;

/**
 * 正規表現コンバータ。<p>
 * 
 * @author Y.Yamashina
 */
public class PatternStringConverter
 implements StringConverter, java.io.Serializable{
    
    private static final long serialVersionUID = 9056240502325078689L;
    
    /**
     * 変換パターン配列。<p>
     */
    protected Object[][] convertObjects;
    
    /**
     * マッチングフラグ。<p>
     */
    protected int matchingFlag = -1;
    
    /**
     * 空の正規表現コンバータを生成する。<p>
     */
    public PatternStringConverter(){
    }
    
    /**
     * 指定されたマッチフラグの正規表現コンバータを生成する。<p>
     *
     * @param flags マッチフラグ
     */
    public PatternStringConverter(int flags){
        setMatchingFlag(flags);
    }
    
    /**
     * 指定されたマッチフラグと変換パターンの正規表現コンバータを生成する。<p>
     *
     * @param fromStrs 変換対象正規表現パターン文字列配列
     * @param toStrs 変換後文字列配列
     */
    public PatternStringConverter(
        int flags,
        String[] fromStrs,
        String[] toStrs
    ){
        setMatchingFlag(flags);
        setConvertStrings(fromStrs, toStrs);
    }
    
    /**
     * 正規表現のマッチングを行う時のマッチフラグを設定する。<p>
     * マッチフラグとは、Pattern.CASE_INSENSITIVE、Pattern.MULTILINE、Pattern.DOTALL、Pattern.UNICODE_CASE、Pattern.CANON_EQ などを含むビットマスクである。
     *
     * @param flags マッチフラグ
     */
    public void setMatchingFlag(int flags){
        // マッチングフラグが変更された場合、patternを再作成
        if(matchingFlag != flags && convertObjects != null){
            for(int i = 0; i < convertObjects.length; i++){
                Pattern pattern = (Pattern)convertObjects[i][0];
                
                Pattern newPattern = null;
                if(flags != -1){
                    newPattern = Pattern.compile(pattern.pattern(), flags);
                } else {
                    newPattern = Pattern.compile(pattern.pattern());
                }
                convertObjects[i][0] = newPattern;
            }
        }
        matchingFlag = flags;
    }
    
    /**
     * 正規表現のマッチングを行う時のマッチフラグを取得する。<p>
     *
     * @return マッチフラグ
     */
    public int getMatchingFlag(){
        return matchingFlag;
    }
    
    /**
     * 変換パターンを設定する。<p>
     *
     * @param fromStrs 変換対象正規表現パターン文字列配列
     * @param toStrs 変換後文字列配列
     */
    public void setConvertStrings(String[] fromStrs, String[] toStrs){
        if(toStrs == null && fromStrs == null){
            convertObjects = null;
        }else if((toStrs == null || fromStrs == null)
            || toStrs.length != fromStrs.length){
            throw new IllegalArgumentException("Invalid ConvertStrings.");
        }else{
            final Object[][] convObjs = new Object[toStrs.length][];
            try{
                for(int i = 0; i < toStrs.length; i++){
                    if(fromStrs[i] == null || toStrs[i] == null){
                        throw new IllegalArgumentException(
                            "Invalid ConvertStrings."
                        );
                    }
                    Pattern pattern = null;
                    if(matchingFlag!=-1) {
                    	pattern = Pattern.compile(fromStrs[i], matchingFlag);
                    } else {
                    	pattern = Pattern.compile(fromStrs[i]);
                    }
                    convObjs[i] = new Object[]{pattern, toStrs[i]};
                }
            }catch(PatternSyntaxException pe){
                //定義されたマッチフラグに対応しないビット値が flags に設定された場合
                throw new IllegalArgumentException("Invalid ConvertStrings.");
            }catch(IllegalArgumentException ie){
                //表現の構文が無効である場合
                throw new IllegalArgumentException("Invalid ConvertStrings.");
            }
            
            convertObjects = convObjs;
        }
    }
    
    // ConverterのJavaDoc
    @Override
    public Object convert(Object obj) throws ConvertException{
        if(obj == null){
            return null;
        }else{
            return convert(
                (String)(obj instanceof String ? obj : String.valueOf(obj))
            );
        }
    }
    
    /**
     * 文字列を変換する。<p>
     * 変換パターン配列を使って変換する。<br>
     *
     * @param str 変換対象の文字列 
     * @return 変換後の文字列
     * @exception ConvertException 変換に失敗した場合
     */
    @Override
    public String convert(String str) throws ConvertException{
        String result = str;
        final Object[][] convObjects = convertObjects;
        
        if(convObjects != null){
            for(int i = 0; i < convObjects.length; i++){
                Pattern pattern = (Pattern)convObjects[i][0];
                
                Matcher matcher = pattern.matcher(result);
                result = matcher.replaceAll(Matcher.quoteReplacement((String)convObjects[i][1]));
            }
        }
        return result;
    }
}
