package com.backfire.arithmetic;

import java.util.ArrayList;
import java.util.Collections;

/**
 * 判牌基类
 * 
 * @author Potter
 */
public abstract class CardJudge {
	public static final int N_0 = 0;
	public static final int N_1 = 1;
	public static final int N_2 = 2;
	public static final int N_3 = 3;
	public static final int N_4 = 4;
	public static final int N_5 = 5;
	public static final int N_6 = 6;
	public static final int N_7 = 7;
	public static final int N_8 = 8;
	public static final int N_9 = 9;
	public static final int N_10 = 10;
	public static final int N_11 = 11;
	public static final int N_12 = 12;
	public static final int N_13 = 13;
	public static final int N_14 = 14;
	public static final int N_15 = 15;
	public static final int N_16 = 16;
	public static final int N_17 = 17;
	public static final int N_18 = 18;
	public static final int N_19 = 19;
	public static final int N_20 = 20;

	public enum CardType {
		CardSingle, // 单牌
		CardPair, // 对子
		CardThreeWithNo, // 三不带
		CardThreeWithOne, // 三带一
		CardThreeWithTwo, // 三带二
		CardFourWithTwo, // 四带二
		CardFourWithTwoPair, // 四带两对
		CardChain, // 顺子
		CardChainPair, // 连对
		CardAirplaneNo, // 飞机不带
		CardAirplaneOne, // 飞机三带一
		CardAirplaneTwo, // 飞机三带二
		CardBombWith_4, // 四张同牌炸弹
		CardBombBoss, // 王炸
		CardBombWith_5, // 5个炸
		CardBombWith_6, // 6个炸
		CardBombWith_7, // 7个炸
		CardBombWith_8, // 8个炸
		CardBigBombBoss, // 至尊王炸
		CardEnd // 结尾符号，用于做错误处理
	};

	public int mCardNum; // 牌型的张数，仅为提高效率;
	public ArrayList<Card> mCardVec; // 避免频繁传参
	public CardReturn mCardReturn;
	
	public CardJudge(){
		mCardNum=0;
		mCardVec=new ArrayList<Card>();
	}

	public static boolean isValid(ArrayList<Card> list, int num) {
		boolean result = false;
		if (list.size() == num) {
			result = true;
		}
		return result;
	}

	/**
	 * 判断传入ArrayList的Card组合成的具体牌型，如果返回为CardEnd，
	 * 表示传入牌型未知，判牌失败,注意：传入牌必须是由大到小排序正确的牌
	 * 
	 * @param myCard
	 * @return
	 */
	public abstract CardReturn judgeCardType(final ArrayList<Card> myCard);

	// CardReturn judgeCardFourType( final ArrayList<Card>& myCard );//4人斗地主


	public void clear() {
		mCardReturn = null;
	}

	/** 判断是否为单牌 **/
	public boolean getSingle() {
		if (null != mCardVec && 0 != mCardVec.size())
			mCardReturn.copy(CardType.CardSingle, mCardVec.get(0),
					mCardVec.size());
		return true;
	}

	/** 判断是否为对子 **/
	public boolean getPair() {
		if ((mCardVec.get(0).getPoint() == Card.PointSmallJoker)
				|| (mCardVec.get(0).getPoint() == Card.PointBigJoker)
				|| (mCardVec.get(1).getPoint() == Card.PointSmallJoker)
				|| (mCardVec.get(1).getPoint() == Card.PointBigJoker)) {
			return false;
		}
		if (judgeSame(mCardVec)) {
			mCardReturn.copy(CardType.CardPair, mCardVec.get(0),
					mCardVec.size());
			return true;
		}
		return false;
	}

	/** 判断是否为王炸 **/
	public boolean getBombBoss() {
		if ((mCardVec.get(0).getPoint() == Card.PointBigJoker)
				&& (mCardVec.get(1).getPoint() == Card.PointSmallJoker)) {
			mCardReturn.copy(CardType.CardBombBoss, mCardVec.get(0),
					mCardVec.size());
			return true;
		}
		return false;
	}

	/** 判断是否为三不带 **/
	public boolean getThreeWithNo() {
		if (judgeSame(mCardVec)) {
			mCardReturn.copy(CardType.CardThreeWithNo, mCardVec.get(0),
					mCardVec.size());
			return true;
		}
		return false;
	}

	/** 判断是否为4同色炸弹 **/
	public boolean getBombWithFour() {
		if (judgeSame(mCardVec)) {
			mCardReturn.copy(CardType.CardBombWith_4, mCardVec.get(0),
					mCardVec.size());
			return true;
		}
		return false;
	}

	/** 判断是否为三带二 **/
	public boolean getThreeWithTwo() {
		if (judgeSame(mCardVec))// 排除5炸
		{
			return false;
		}
		if (judgeEqual(mCardVec.get(0), mCardVec.get(1))
				&& judgeEqual(mCardVec.get(2), mCardVec.get(4))) {
			mCardReturn.copy(CardType.CardThreeWithTwo, mCardVec.get(2),
					mCardVec.size());
			return true;
		} else if (judgeEqual(mCardVec.get(0), mCardVec.get(2))
				&& judgeEqual(mCardVec.get(3), mCardVec.get(4))) {
			mCardReturn.copy(CardType.CardThreeWithTwo, mCardVec.get(0),
					mCardVec.size());
			return true;
		}
		return false;
	}

	/** 判断是否为顺子 **/
	public boolean getJunko() {
		if (mCardNum < 5) {
			return false;
		}
		if (mCardVec.get(0).getPoint() >= Card.Point2) // 顺子的最大数据不能大于等于2
		{
			return false;
		}
		for (int i = 0; i < mCardNum - 1; ++i) {
			if (mCardVec.get(i).getPoint() - mCardVec.get(i + 1).getPoint() != 1) {
				return false;
			}
		}
		mCardReturn.copy(CardType.CardChain, mCardVec.get(0), mCardVec.size());
		return true;
	}

	/** 判断是否为连对 **/
	public boolean getJunkoPair() {
		if (mCardNum < 6)// 3对以上
		{
			return false;
		}
		if ((mCardNum % 2) != 0)// 双数牌
		{
			return false;
		}
		if (mCardVec.get(0).getPoint() >= Card.Point2) // 顺子的最大数据不能大于等于2
		{
			return false;
		}
		for (int i = 0; i < mCardNum / 2; ++i)// 一旦出现双数相连不等的牌就不是顺子
		{
			if (!judgeEqual(mCardVec.get(i * 2), mCardVec.get(i * 2 + 1))) {
				return false;
			}
		}
		for (int i = 0; i < (mCardNum / 2 - 1); ++i) {
			if (mCardVec.get(i * 2).getPoint()
					- mCardVec.get((i + 1) * 2).getPoint() != 1) {
				return false;
			}
		}
		mCardReturn.copy(CardType.CardChainPair, mCardVec.get(0),
				mCardVec.size());
		return true;
	}

	/** 判断是否为飞机三不带 **/
	public boolean getAirplaneNo(final ArrayList<Card> myCard) {
		if (judgeSame(mCardVec))// 排除6炸
		{
			return false;
		}
		ArrayList<Card> myCardTest = mCardVec;
		if (myCard != null) {
			mCardNum = myCard.size();
			myCardTest = myCard;

		}
		if (mCardNum < 6)// 2对以上
			return false;

		if ((mCardNum % 3) != 0)// 三数牌
			return false;

		if (myCardTest.get(0).getPoint() >= Card.Point2) // 三带一的最大数据不能大于等于2
			return false;

		for (int i = 0; i < mCardNum / 3; ++i)// 一旦出现双数相连不等的牌就不是三不带飞机
		{
			if (!judgeEqual(myCardTest.get(i * 3), myCardTest.get(i * 3 + 2))) {
				return false;
			}
		}

		for (int i = 0; i < mCardNum / 3 - 1; ++i) {
			if (myCardTest.get(i * 3).getPoint()
					- myCardTest.get((i + 1) * 3).getPoint() != 1) {
				return false;
			}
		}
		mCardReturn.copy(CardType.CardAirplaneNo, myCardTest.get(0),
				mCardVec.size());
		return true;
	}

	/** 判断是否为飞机三带二 **/
	public boolean getAirplaneTwo() {
		if (mCardNum < 10)// 2对以上
			return false;

		if ((mCardNum % 5) != 0)// 四数牌
			return false;

		int iCard = judgeAirplaneHead(mCardVec);
		if (iCard == 2)
			return false;

		for (; iCard >= (iCard + (mCardNum / 5)); ++iCard) // 查看飞机头到飞机尾是否是3个一连
		{
			if (find(Card.changePoint(iCard), mCardVec) >= 3) {
				continue;
			} else {
				return false;
			}
		}
		int iNum = 0;
		for (int i = 0; i < mCardNum; ++i) {
			/*Card my = new Card(Card.Club, Card.changePoint(iCard));
			Card you = new Card(Card.Club, Card.changePoint(iCard
					- (mCardNum / 5 - 1)));*/
			if (((int) mCardVec.get(i).getPoint() <= Card.changePoint(iCard))
					&& ((int) mCardVec.get(i).getPoint() >= Card
							.changePoint(iCard - (mCardNum / 5 - 1))))
				continue;
			if (i == mCardNum - 1)
				continue;
			if (mCardVec.get(i).getPoint() == mCardVec.get(i + 1).getPoint()) {
				i++;
				iNum++;
			}
		}
		if (iNum != mCardNum / 5) {
			return false;
		}
		Card card = new Card(Card.Spade, Card.changePoint(iCard));
		mCardReturn.copy(CardType.CardAirplaneTwo, card, mCardVec.size());
		return true;
	}

	/** 判断ArrayList中元素是否一样 **/
	public boolean judgeSame(final ArrayList<Card> myCard) {
		boolean bReturnData = true;
		for (int iX = 0; iX < myCard.size() - 1; ++iX) {
			if (judgeEqual(myCard.get(iX), myCard.get(iX + 1)))// 相邻两个是否相同
			{
				continue;
			} else {
				bReturnData = false;
				break;
			}
		}
		return bReturnData;
	}

	/** 找到飞机head **/
	public int judgeAirplaneHead(final ArrayList<Card> myCard) {
		int iCard = Card.PointA;
		for (; iCard >= Card.Point3; --iCard) // 找到飞机头
		{
			if (find(Card.changePoint(iCard), myCard, myCard.size()) >= 3) {
				if ((find(Card.changePoint(iCard - 1), myCard, myCard.size()) >= 3)) {
					if (mCardNum < 20)// 避免出现333,444,555,888,999,10,J,Q,K,A
						break;

					if (find(Card.changePoint(iCard - 2), myCard, myCard.size()) >= 3)
						break;
				}
			}
		}
		return iCard;
	}

	/** 比较相等 **/
	public boolean judgeEqual(Card dThis, Card dOther) {
		return dThis.isSamePoint(dOther);
	}

	public int find(int myPoint, final ArrayList<Card> myCard) {
		int iNum = 0;
		for (int i = 0; i < mCardNum; ++i) {
			if (myCard.get(i).getPoint() == myPoint) {
				iNum++;
			}
		}
		return iNum;
	}

	public int find(int myPoint, final ArrayList<Card> myCard, int iSize) {
		int iNum = 0;
		for (int i = 0; i < iSize; ++i) {
			if (myCard.get(i).getPoint() == myPoint) {
				iNum++;
			}
		}
		return iNum;
	}

	public void sortVec(ArrayList<Card> myVec) {
		Collections.sort(myVec, new CardAssist.Desc());
	}
}
