/*
 * $Id: StringReplacer.java 220 2007-07-16 10:32:15Z sugimotokenichi $
 * Copyright (C) 2004-2006 SUGIMOTO Ken-ichi
 * 作成日: 2006/05/11
 */
package feat2.impl;

import org.apache.commons.lang.StringUtils;

/**
 * 文字列の置き換えをするクラス。
 * @author SUGIMOTO Ken-ichi
 */
public class StringReplacer {

    //private char[][] searchStrs;
    private String[] searchStrs;
    private char[][] replaceStrs;
    private long searchHash;


    public StringReplacer(String[] searchStrs, String[] replaceStrs) {

        /*this.searchStrs = new char[searchStrs.length][];
        for (int i = 0; i < searchStrs.length; i++) {
            this.searchStrs[i] = searchStrs[i].toCharArray();
        }*/
        this.searchStrs = searchStrs;

        this.replaceStrs = new char[replaceStrs.length][];
        for (int i = 0; i < replaceStrs.length; i++) {
            this.replaceStrs[i] = replaceStrs[i].toCharArray();
        }

        searchHash = getStringArrayHash(searchStrs);

    }


    public StringReplacer(String searchChars, String replaceChars) {

        this.searchStrs = new String[searchChars.length()];
        this.replaceStrs = new char[searchChars.length()][];
        for (int i = 0; i < searchChars.length(); i++) {
            this.searchStrs[i] = Character.toString(searchChars.charAt(i));
            this.replaceStrs[i] = new char[] {replaceChars.charAt(i)};
        }

        searchHash = getStringArrayHash(searchStrs);

    }


    /*
    public String replace(String str) {

        int i;
        char[] o = new char[str.length() * 12 / 10];
        char[] c = str.toCharArray();
        int count = 0;
        int strlen = str.length();
        int oidx = 0;

        for (i = 0; i < strlen; ) {

            long hash = 1L << (c[i] % 64);

            if ( (hash & searchHash) != 0 ) {

                boolean replaceFlag = false;

                for (int j = 0; j < searchStrs.length; j++) {

                    if ( match(c, i, searchStrs[j], 0, searchStrs[j].length) ) {

                        copy(replaceStrs[j], 0, o, oidx, replaceStrs[j].length);
                        oidx += replaceStrs[j].length;
                        i += searchStrs[j].length;
                        count++;
                        replaceFlag = true;
                        break;

                    }

                }

                if ( !replaceFlag )
                    o[oidx++] = c[i++];

            }

            else {

                o[oidx++] = c[i++];

            }

        }

        if ( count > 0 )
            return new String(o, 0, oidx);
        else
            return str;

    }
    */


    public String replace(String str) {

        int i;
        char[] o = new char[str.length() * 12 / 10];
        int count = 0;
        int strlen = str.length();
        int oidx = 0;

        for (i = 0; i < strlen; ) {

            char c = str.charAt(i);
            long hash = 1L << (c % 64);

            if ( (hash & searchHash) != 0 ) {

                int replaceIdx = -1;


                for (int j = 0; j < searchStrs.length; j++) {

                    if ( searchStrs[j].length() == 1 ) {

                        if ( searchStrs[j].charAt(0) == c ) {
                            replaceIdx = j;
                            break;
                        }

                    }

                    else {

                        if ( str.regionMatches(i, searchStrs[j], 0, searchStrs[j].length()) ) {
                            replaceIdx = j;
                            break;
                        }

                    }

                }

                if ( replaceIdx > -1 ) {
                    copy(replaceStrs[replaceIdx], 0, o, oidx, replaceStrs[replaceIdx].length);
                    oidx += replaceStrs[replaceIdx].length;
                    i += searchStrs[replaceIdx].length();
                    count++;
                }
                else {
                    o[oidx++] = c;
                    i++;
                }

            }

            else {

                o[oidx++] = c;
                i++;

            }

        }

        if ( count > 0 )
            return new String(o, 0, oidx);
        else
            return str;

    }



    private char[] copy(char[] src, int srcOffset, char[] dest, int destOffset, int len) {

        // コピー先が小さすぎたら拡張

        if ( destOffset + len > dest.length ) {
            char[] newDest = new char[dest.length * 12/10 + len];
            System.arraycopy(dest, 0, newDest, 0, dest.length);
            dest = newDest;
        }

        System.arraycopy(src, srcOffset, dest, destOffset, len);

        return dest;

    }

    private long getStringArrayHash(String[] a) {

        long ret = 0;
        for (int i = 0; i < a.length; i++) {
            ret |= 1L << (a[i].charAt(0) % 64);
        }
        return ret;

    }


    private static final int LOOP = 1000000;
    public static void main(String[] args) {

        String str = "--012-----------GHI---------ABCDEF-----56789----------3345---XYXYXYXYX-----------------";
        String[] test = str.split("");
        String[] search = {"012", "345", "678", "ABC", "DEF", "GHI", "XYX", "x"};
        String[] replace = {"{012}", "{345}", "{678}", "a", "d", "g", "x", "?"};


        StringReplacer rep = new StringReplacer(search, replace);
        String result = null;
        long start = System.currentTimeMillis();
        for(int i=0; i<LOOP; i++) {
            result = rep.replace(str);
        }
        double t = (double)(System.currentTimeMillis()-start)/LOOP;
        System.out.println(result);
        System.out.println("StringReplacer:"+t);


        start = System.currentTimeMillis();
        for(int i=0; i<LOOP; i++) {
            result = str;
            for (int j = 0; j < search.length; j++) {
                result = StringUtils.replace(result, search[j], replace[j]);
            }
        }
        t = (double)(System.currentTimeMillis()-start)/LOOP;
        System.out.println(result);
        System.out.println("StringUtils.replace():"+t);



        String searchChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String replacechars = "..........abcdefghijklmnopqrstuvwxyz";
        rep = new StringReplacer(searchChars, replacechars);
        result = null;
        start = System.currentTimeMillis();
        for(int i=0; i<LOOP; i++) {
            result = rep.replace(str);
        }
        t = (double)(System.currentTimeMillis()-start)/LOOP;
        System.out.println(result);
        System.out.println("StringReplacer(chars):"+t);


        result = null;
        start = System.currentTimeMillis();
        for(int i=0; i<LOOP; i++) {
            result = StringUtils.replaceChars(str, searchChars, replacechars);
        }
        t = (double)(System.currentTimeMillis()-start)/LOOP;
        System.out.println(result);
        System.out.println("StringUtils.replaceChars():"+t);
    }


}
