package extend.zp.uitl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

import extend.zp.OpCard;
import extend.zp.RuleWeight;

public class WinCardNew {
	private boolean						isJiang	= false;
	private List<Integer>				cardList;
	private Stack<List<List<OpCard>>>	opCardStack;
	private List<List<OpCard>>			lastOpCard;
	private Integer						addCard;
	private int							huxi	= 0;
	private List<OpCard>				opCardList;

	public List<WinOpCard>				winList;

	public boolean checkHu() {
		try {

			int card = addCard == 0 ? (this.cardList.size() > 0 ? this.cardList.get(0) : 0) : addCard;
			List<OpCard> list = new ArrayList<OpCard>();
			if (card > 0) {
				list = groupCard(card, this.cardList, true);
			} else if (card == 0) {
				addWinOpCard(huxi, null);
				return true;
			}
			List<Integer> tempCardList = new ArrayList<>();
			for (OpCard opCard : list) {
				tempCardList.clear();
				tempCardList.addAll(cardList);
				Collections.sort(tempCardList);
				removeOpCard(tempCardList, opCard);
				List<OpCard> opCardS = new ArrayList<>();
				List<List<OpCard>> opCardS_1 = new ArrayList<>();
				opCardS.add(opCard);
				opCardS_1.add(opCardS);
				this.opCardStack.push(opCardS_1);
				checkWin(tempCardList);
			}
		} catch (Exception e) {
			return false;
		}
		return Win();
	}


	private boolean Win() {
		List<Integer> tempCardList = new ArrayList<>();
		boolean hu, isExJiang;
		for (List<OpCard> opCards : this.lastOpCard) {
			isExJiang = false;
			tempCardList.clear();
			tempCardList.addAll(cardList);
			hu = false;
			int huxi = this.huxi;
			for (OpCard tempOpCard : opCards) {
				removeOpCard(tempCardList, tempOpCard);
				if (tempOpCard.type == RuleWeight.TYPE_JIANG) {
					isExJiang = true;
					continue;
				}
				huxi += tempOpCard.huXi;
			}

			hu = isJiang ? isExJiang && tempCardList.size() == 0 : tempCardList.size() == 0;
			if (hu) {
				addWinOpCard(huxi, opCards);
			}
		}
		return !winList.isEmpty();
	}

	private void removeOpCard(List<Integer> cards, OpCard opCard) {
		if (opCard.card1 > 0) {
			CardUtil.removeCard(cards, opCard.card1, 1);
		}
		if (opCard.card2 > 0) {
			CardUtil.removeCard(cards, opCard.card2, 1);
		}
		if (opCard.card3 > 0) {
			CardUtil.removeCard(cards, opCard.card3, 1);
		}
	}

	private boolean isExJiang(List<List<OpCard>> list) {
		for (List<OpCard> opCard : list) {
			for (OpCard opCard2 : opCard) {
				if (opCard2.type == RuleWeight.TYPE_JIANG) {
					return false;
				}
			}
		}
		return true;
	}

	private void checkWin(List<Integer> cardList) throws ClassNotFoundException, IOException {
		List<List<OpCard>> opCards = this.opCardStack.pop();
		if (opCards.isEmpty()) {
			return;
		}
		List<List<OpCard>> list = new ArrayList<>();
		if (cardList.size() == 0) {
			list = CardUtil.deepCopy(opCards);
			this.lastOpCard.addAll(list);
			return;
		}
		List<OpCard> oplist = null, opList2 = null;
		for (Integer card : cardList) {
			oplist = groupCard(card, cardList, isExJiang(opCards));
			if (oplist.size() > 0) {
				break;
			}
		}
		if (oplist.size() > 0) {
			List<Integer> tempCardList = new ArrayList<>();
			for (OpCard opCard : oplist) {
				tempCardList.clear();
				tempCardList.addAll(cardList);
				list = new ArrayList<>();
				removeOpCard(tempCardList, opCard);
				list = CardUtil.deepCopy(opCards);
				for (List<OpCard> tempOpCard : list) {
					tempOpCard.add(opCard);
				}
				for (Integer card : tempCardList) {
					opList2 = groupCard(card, tempCardList, isExJiang(list));
					if (opList2.size() > 0) {
						break;
					}
				}
				if (opList2 != null && opList2.size() > 0) {
					this.opCardStack.push(list);
					checkWin(tempCardList);
				} else {
					this.lastOpCard.addAll(list);
				}

			}
		} else {
			list = new ArrayList<>();
			list = CardUtil.deepCopy(opCards);
			this.lastOpCard.addAll(list);
		}

	}

	/**
	 * ĳ����Ч���
	 * 
	 * @param card
	 * @return
	 */
	private List<OpCard> groupCard(int card, List<Integer> cardList, boolean first) {
		List<OpCard> opCardList = new ArrayList<>();
		List<Integer> tempList = new ArrayList<>();
		tempList.addAll(cardList);
		shunzi1_10(card, opCardList, tempList);
		shunzi2710(card, opCardList, tempList);
		jiaopai(card, opCardList, tempList);
		kan(card, opCardList, tempList);
		if (isJiang && first) {
			jiang(card, opCardList, tempList);
		}
		return opCardList;
	}

	/**
	 * ��һ�Խ�
	 */
	private void jiang(int card, List<OpCard> list, List<Integer> cardList) {
		List<Integer> tempList = new ArrayList<>();
		tempList.addAll(cardList);
		if (isJiang) {
			if (CardUtil.cardNum(card, cardList) >= 2) {
				OpCard opCard = new OpCard();
				opCard.card1 = card;
				opCard.card2 = card;
				opCard.huXi = 0;
				opCard.type = RuleWeight.TYPE_JIANG;
				list.add(opCard);
			}
		}
	}

	/**
	 * ��С 1 2 3 4 5 6 7 8 9 ˳��
	 * 
	 * @param card
	 */
	private void shunzi1_10(int card, List<OpCard> list, List<Integer> cardList) {
		List<Integer> tempList = new ArrayList<>();
		tempList.addAll(cardList);
		CardUtil.distinctList(tempList);
		Collections.sort(tempList);
		List<Integer> opCardList = new ArrayList<>();
		// AB (C)
		if (CardUtil.cardNum(card - 2, cardList) >= 1 && CardUtil.cardNum(card - 1, cardList) >= 1) {
			opCardList.clear();
			opCardList.add(card);
			opCardList.add(card - 1);
			opCardList.add(card - 2);
			list.add(addOpCard(opCardList));

		}
		// (A) B C
		if (CardUtil.cardNum(card + 1, cardList) >= 1 && CardUtil.cardNum(card + 2, cardList) >= 1) {
			opCardList.clear();
			opCardList.add(card);
			opCardList.add(card + 1);
			opCardList.add(card + 2);
			list.add(addOpCard(opCardList));
		}
		// A (B) C
		if (CardUtil.cardNum(card - 1, cardList) >= 1 && CardUtil.cardNum(card + 1, cardList) >= 1) {
			opCardList.clear();
			opCardList.add(card);
			opCardList.add(card - 1);
			opCardList.add(card + 1);
			list.add(addOpCard(opCardList));
		}
	}

	private OpCard addOpCard(List<Integer> opCardList) {
		Collections.sort(opCardList);
		int huXi = 0;
		// 123 ˳���к�Ϣ С3��6
		if (opCardList.get(0) % 100 == 1) {
			huXi = Paixing.caclHuxi(RuleWeight.TYPE_CHOW, opCardList.get(0));
		}
		OpCard opCard = new OpCard(RuleWeight.TYPE_CHOW, opCardList.get(0), opCardList.get(1), opCardList.get(2), huXi);
		return opCard;
	}

	/**
	 * ��С 2 7 10˳�� �к�Ϣ С3��6
	 * 
	 * @param card
	 */
	private void shunzi2710(int card, List<OpCard> list, List<Integer> cardList) {
		if (card % 100 == 2 || card % 100 == 7 || card % 100 == 10) {
			List<Integer> tempList = new ArrayList<>();
			tempList.addAll(cardList);
			CardUtil.distinctList(tempList);
			Collections.sort(tempList);
			// (2) 7 10
			List<Integer> opCardList = new ArrayList<>();
			if (CardUtil.cardNum(card + 5, cardList) >= 1 && CardUtil.cardNum(card + 8, cardList) >= 1) {
				opCardList.add(card);
				opCardList.add(card + 5);
				opCardList.add(card + 8);
				// 2 (7) 10
			} else if (CardUtil.cardNum(card - 5, cardList) >= 1 && CardUtil.cardNum(card + 3, cardList) >= 1) {
				opCardList.add(card);
				opCardList.add(card - 5);
				opCardList.add(card + 3);
				// 2 7 (10)
			} else if (CardUtil.cardNum(card - 8, cardList) >= 1 && CardUtil.cardNum(card - 3, cardList) >= 1) {
				opCardList.add(card);
				opCardList.add(card - 3);
				opCardList.add(card - 8);
			}
			if (opCardList.size() > 0) {
				Collections.sort(opCardList);
				int huXi = Paixing.caclHuxi(RuleWeight.TYPE_CHOW, opCardList.get(0));
				OpCard opCard = new OpCard(RuleWeight.TYPE_CHOW, opCardList.get(0), opCardList.get(1), opCardList.get(2), huXi);
				list.add(opCard);
				if (opCard.card1 != card) {
					CardUtil.removeCard(tempList, opCard.card1, 1);
				}
				if (opCard.card2 != card) {
					CardUtil.removeCard(tempList, opCard.card2, 1);
				}
				if (opCard.card3 != card) {
					CardUtil.removeCard(tempList, opCard.card3, 1);
				}
				shunzi2710(card, list, tempList);
			}
			return;
		}
	}

	/**
	 * aaA AAa ������ ������ û��Ϣ
	 * 
	 * @param card
	 */
	private void jiaopai(int card, List<OpCard> list, List<Integer> cardList) {
		List<Integer> tempList = new ArrayList<>();
		tempList.addAll(cardList);
		int type = card / 100;
		int bg_num = type == 1 ? 100 : -100;
		int bi_card = card + bg_num;
		// aaA
		if (CardUtil.cardNum(card, cardList) >= 2 && CardUtil.cardNum(bi_card, cardList) >= 1) {
			OpCard opCard = new OpCard(RuleWeight.TYPE_CHOW, card, card, bi_card, 0);
			list.add(opCard);
			// AAa
		} else if (CardUtil.cardNum(card, cardList) >= 1 && CardUtil.cardNum(bi_card, cardList) >= 2) {
			OpCard opCard = new OpCard(RuleWeight.TYPE_CHOW, card, bi_card, bi_card, 0);
			list.add(opCard);
		}
	}

	/**
	 * 3��
	 * 
	 * @param card
	 * @param list
	 */
	private void kan(int card, List<OpCard> list, List<Integer> cardList) {
		List<Integer> tempList = new ArrayList<>();
		List<Integer> opCardList = new ArrayList<>();
		tempList.addAll(cardList);
		if (CardUtil.cardNum(card, cardList) == 3) {
			opCardList.add(card);
			opCardList.add(card);
			opCardList.add(card);
			int huxi = Paixing.caclHuxi(RuleWeight.TYPE_PONG, card);
			OpCard opCard = new OpCard(RuleWeight.TYPE_PONG, opCardList.get(0), opCardList.get(1), opCardList.get(2), huxi);
			list.add(opCard);
		}
	}

	private void addWinOpCard(int huxi, List<OpCard> opCard) {
		if (opCard == null) {
			opCard = new ArrayList<>();
		}
		opCard.addAll(this.opCardList);
		WinOpCard wo = new WinOpCard(opCard, huxi);
		winList.add(wo);
	}

	public static void main(String[] args) throws ClassNotFoundException, IOException {
		List<Integer> list = new ArrayList<>();
		String str = "106";
		for (String card : str.split(", ")) {
			list.add(Integer.parseInt(card));
		}
		List<OpCard> op = new ArrayList<OpCard>();
		OpCard opCard=new OpCard(3, 102, 102, 102, 9);
		op.add(opCard);
		WinCardNew winCard2 = new WinCardNew(list, 106, 9, true, op);
		/* op = winCard2.groupCard(207); */
		System.out.println(winCard2.checkHu());
		winCard2.winList.forEach(wl -> System.out.println(wl.toString()));

	}

	/**
	 * 
	 * @param cardInhand
	 *            :����,��������
	 * @param addCard
	 *            : �Ӵ����Ƿ��ܺ���������������������Ҫ��0
	 * @param huxi
	 *            ��������еĺ�Ϣ
	 * @param isJiang
	 *            ���Ƿ���Ҫ��
	 */
	public WinCardNew(List<Integer> cardInhand, int addCard, int huxi, boolean isJiang, List<OpCard> opCardList) {
		this.opCardStack = new Stack<>();
		this.lastOpCard = new ArrayList<>();
		this.cardList = new ArrayList<Integer>(cardInhand);
		this.opCardList = new ArrayList<>(opCardList);
		if (addCard > 0) {
			this.cardList.add(addCard);
		}
		Collections.sort(this.cardList);
		this.isJiang = isJiang;
		this.addCard = addCard;
		this.huxi = huxi;
		this.winList = new ArrayList<>();
	}
}
