/*
 * Copyright 2008 nori090
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.coderepos.nori090.df;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author nori090
 * @version $Rev: 225 $ $Date: 2008-11-03 04:23:09 +0900 (Mon, 03 Nov 2008) $
 */
public class Card {
    // カードリスト
    TYPE[] list;

    public Card( String cards ) {
        int size = ( cards.length() / 2 );
        list = new TYPE[size];
        char[] cs = cards.toCharArray();
        for ( int i = 0; i < cards.length(); i += 2 ) {
            String s = new StringBuilder().append( cs[i] ).append( cs[i + 1] ).toString().toUpperCase();
            TYPE t = TYPE.valueOf( s );
            list[i / 2] = t;
        }
    }

    public Card( TYPE... cards ) {
        list = new TYPE[cards.length];
        System.arraycopy( cards, 0, list, 0, cards.length );
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for ( TYPE t : list ) {
            sb.append( t.toString() );
        }
        return sb.toString();
    }

    @Override
    protected Object clone()
        throws CloneNotSupportedException {
        return new Card( this.toString() );
    }

    enum TYPE {
        CA,
        C2,
        C3,
        C4,
        C5,
        C6,
        C7,
        C8,
        C9,
        C0,
        CJ,
        CQ,
        CK,
        HA,
        H2,
        H3,
        H4,
        H5,
        H6,
        H7,
        H8,
        H9,
        H0,
        HJ,
        HQ,
        HK,
        DA,
        D2,
        D3,
        D4,
        D5,
        D6,
        D7,
        D8,
        D9,
        D0,
        DJ,
        DQ,
        DK,
        SA,
        S2,
        S3,
        S4,
        S5,
        S6,
        S7,
        S8,
        S9,
        S0,
        SJ,
        SQ,
        SK,
        FF,
        PP;

        private static int[] revolve_point = { 0, 0, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 16 };

        public int intValue() {
            if ( this == PP ) {
                return -1;
            }
            if ( this == FF ) {
                return 16;
            }
            char[] cs = this.name().toCharArray();
            if ( cs[1] == 'A' )
                return 14;
            if ( cs[1] == '2' )
                return 15;
            if ( cs[1] == '0' )
                return 10;
            if ( cs[1] == 'J' )
                return 11;
            if ( cs[1] == 'Q' )
                return 12;
            if ( cs[1] == 'K' )
                return 13;
            return cs[1] - 48;
        }

        public int intValue( boolean isRevolve ) {
            if ( !isRevolve )
                return this.intValue();
            int base = this.intValue();
            if ( base > 0 ) {
                return revolve_point[base];
            }
            return base;
        }
    }

    public static Comparator<TYPE> getComparator( final boolean isRevolve ) {
        // スートでまとめて、昇順ソート
        return new Comparator<TYPE>() {
            @Override
            public int compare( TYPE o1, TYPE o2 ) {
                Character c1 = o1.name().toCharArray()[0];
                Character c2 = o2.name().toCharArray()[0];
                int comp = c1.compareTo( c2 );
                if ( comp == 0 ) {
                    Integer i1 = o1.intValue( isRevolve );
                    Integer i2 = o2.intValue( isRevolve );
                    return i1.compareTo( i2 );
                }
                else {
                    return comp;
                }
            }
        };
    }

    public static Comparator<TYPE> getPowerComparator( final boolean isRevolve, boolean isAsc ) {
        if ( !isAsc ) {
            // int値で降順ソート
            return new Comparator<TYPE>() {
                @Override
                public int compare( TYPE o1, TYPE o2 ) {
                    Integer i1 = o1.intValue( isRevolve );
                    Integer i2 = o2.intValue( isRevolve );
                    return i2.compareTo( i1 );
                }
            };
        }
        // int値で昇順ソート
        return new Comparator<TYPE>() {
            @Override
            public int compare( TYPE o1, TYPE o2 ) {
                Integer i1 = o1.intValue( isRevolve );
                Integer i2 = o2.intValue( isRevolve );
                return i1.compareTo( i2 );
            }
        };
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode( list );
        return result;
    }

    @Override
    public boolean equals( Object obj ) {
        if ( this == obj ) {
            return true;
        }
        if ( obj == null ) {
            return false;
        }
        if ( getClass() == obj.getClass() ) {
            final Card other = (Card) obj;

            TYPE[] otherlist = new TYPE[other.list.length];
            System.arraycopy( other.list, 0, otherlist, 0, other.list.length );
            TYPE[] thislist = new TYPE[list.length];
            System.arraycopy( list, 0, thislist, 0, list.length );
            if ( !Arrays.equals( thislist, otherlist ) ) {
                return false;
            }
        }
        // カード１枚の時も比較する。
        else if ( obj instanceof TYPE && list.length == 1 ) {
            return list[0].equals( (TYPE) obj );
        }
        // カード複数枚も比較する。
        else if ( obj instanceof TYPE[] ) {
            final TYPE[] other = (TYPE[]) obj;
            TYPE[] otherlist = new TYPE[other.length];
            System.arraycopy( other, 0, otherlist, 0, other.length );
            TYPE[] thislist = new TYPE[list.length];
            System.arraycopy( list, 0, thislist, 0, list.length );
            if ( !Arrays.equals( thislist, otherlist ) ) {
                return false;
            }
        }
        else {
            return false;
        }
        return true;
    }

    public static void main( String[] args ) {
        for ( TYPE t : TYPE.values() ) {
            System.out.println( t + ": " + t.intValue() + " / " + t.intValue( true ) );
        }
    }
}
