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 com.game.Util;

import extend.zp.Config;
import extend.zp.EXPlayer;
import extend.zp.OpCard;
import extend.zp.RuleWeight;


public class WinCard {
	private boolean						isJiang	= false;
	private List<Integer>				cardList;
	private List<Integer>				cardhand;
	private Stack<List<List<OpCard>>>	opCardStack;
	private List<List<OpCard>>			lastOpCard;
	private Integer						addCard;
	private EXPlayer 					player;
	public List<OpCard>					maxOpCard;
	public int							maxHuXi	= -1;
	public int							allHuXi	= -1;
	private int							huxi	= 0;
	private List<OpCard>				opCardList;
	
	public boolean checkHu() throws ClassNotFoundException, IOException {
	
		boolean existHandCard = this.cardList.size() > 0;
		int card = addCard == 0 ? (existHandCard ? this.cardList.get(0) : 0) : addCard;
		List<OpCard> list = new ArrayList<OpCard>();
		if (card > 0) {
			list = groupCard(card, this.cardList, true);
		} else {
			maxHuXi = huxi;
			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);
		}
		return maxHuxi();
	}

	private void addCheckTyCardList(List<Integer> opmty, List<Integer> opaty, List<Integer> tyCardList) {
		tyCardList.addAll(cardList);
		for (OpCard opCard : opCardList) {
			if (opCard.type == RuleWeight.TYPE_CHOW) {
				tyCardList.add(opCard.card1);
				tyCardList.add(opCard.card2);
				tyCardList.add(opCard.card3);
			}
		}
		for (OpCard opCard : opCardList) {
			if (opCard.type == RuleWeight.TYPE_WEI && opCard.huXi < 5) {
				opaty.add(opCard.card1);
			}else if (opCard.type == RuleWeight.TYPE_PONG && opCard.huXi < 5) {
				opmty.add(opCard.card1);
			}
		}
	}
	
	private int changeHuXi(List<OpCard> tempOpCardList, List<OpCard> opCards, int totalHuXi, int huXi, int card) {
		for (OpCard opCard : opCards) {
			if ((opCard.type == RuleWeight.TYPE_KAN || opCard.type == RuleWeight.TYPE_PONG) 
					&& opCard.card1 == card) {
				totalHuXi += huXi - opCard.huXi;
				opCard.huXi = huXi;
				return totalHuXi;
			}
		}
		for (OpCard opCard : tempOpCardList) {
			if ((opCard.type == RuleWeight.TYPE_WEI || opCard.type == RuleWeight.TYPE_PONG) 
					&& opCard.card1 == card) {
				totalHuXi += huXi - opCard.huXi;
				opCard.huXi = huXi;
			}
		}
		return totalHuXi;
	}
	
	private void checkKan() {
		List<Integer> tempCardList = new ArrayList<>();
		List<List<OpCard>> OpCardList = new ArrayList<>();
		for (List<OpCard> opCards : this.lastOpCard) {
			tempCardList.clear();
			tempCardList.addAll(cardList);
			boolean chi = false , pong = false;
			for (OpCard tempOpCard : opCards) {
				if (tempOpCard.type == RuleWeight.TYPE_CHOW && (tempOpCard.card1 == addCard || 
						tempOpCard.card2 == addCard || tempOpCard.card3 == addCard)) {
					chi = true;
				}else if (tempOpCard.type == RuleWeight.TYPE_PONG && tempOpCard.card1 == addCard) {
					pong = true;
				}
				removeOpCard(tempCardList, tempOpCard);
			}
			if (tempCardList.size() == 0 && chi && pong) {
				List<OpCard> opCard = new ArrayList<>();
				for (OpCard tempOpCard : opCards) {
					if (tempOpCard.type == RuleWeight.TYPE_PONG && tempOpCard.card1 == addCard) {
						opCard.add(new OpCard(RuleWeight.TYPE_KAN, addCard, addCard,
								addCard, CardUtil.checkHongCard(addCard) ? 4 : 3));
					}else {
						opCard.add(tempOpCard);
					}
				}
				OpCardList.add(opCard);
			}
		}
		if (OpCardList.size() > 0 ) 
			this.lastOpCard.addAll(OpCardList);
	}


	private boolean maxHuxi() {
		List<Integer> tempCardList = new ArrayList<>(), opmty = new ArrayList<>(),
		opaty = new ArrayList<>(), tyCardList = new ArrayList<>();
		boolean hu;
		addCheckTyCardList(opmty, opaty, tyCardList);
		checkKan();
		for (List<OpCard> opCards : this.lastOpCard) {
			tempCardList.clear();
			tempCardList.addAll(cardList);
			hu = false;
			int huxi = this.huxi;
			List<Integer> mty = new ArrayList<>(), aty = new ArrayList<>(), tempTyCardList = new ArrayList<>(tyCardList);
			mty.addAll(opmty);
			aty.addAll(opaty);
			List<OpCard> tempOpCardList = new ArrayList<>(this.opCardList); 
			boolean isZhuanWan = false;
			for (OpCard tempOpCard : opCards) {
				removeOpCard(tempCardList, tempOpCard);
				if (tempOpCard.type == RuleWeight.TYPE_JIANG) {
					for (OpCard opCard : opCards) {
						if (opCard.type == RuleWeight.TYPE_CHOW) {
							if (opCard.card1 == tempOpCard.card1 || opCard.card2 == tempOpCard.card1 
									|| opCard.card3 == tempOpCard.card1) {
								tempOpCard.huXi = tempOpCard.huXi == 0 ? 2 : 3;
								isZhuanWan = true;
								break;
							}
						}
					}
					if (!isZhuanWan) {
						for (OpCard opCard : opCardList) {
							if (opCard.type == RuleWeight.TYPE_CHOW) {
								if (opCard.card1 == tempOpCard.card1 || opCard.card2 == tempOpCard.card1 
										|| opCard.card3 == tempOpCard.card1) {
									tempOpCard.huXi = tempOpCard.huXi == 0 ? 2 : 3;
									isZhuanWan = true;
									break;
								}
							}
						}
					}
				}else if (tempOpCard.type == RuleWeight.TYPE_PONG) {
					mty.add(tempOpCard.card1);
					Util.removeCard(tempTyCardList, tempOpCard.card1, 3);
				}else if (tempOpCard.type == RuleWeight.TYPE_KAN) {
					aty.add(tempOpCard.card1);
					Util.removeCard(tempTyCardList, tempOpCard.card1, 3);
				}
				huxi += tempOpCard.huXi;
			}
			if (tempCardList.size() == 0) {
				hu = true;
				for (Integer anCard : aty) {
					if (tempTyCardList.contains(anCard)) {
						huxi = changeHuXi(tempOpCardList, opCards, huxi, CardUtil.checkHongCard(anCard) ? 8 : 6, anCard);
					}
				}
				for (Integer mingCard : mty) {
					if (tempTyCardList.contains(mingCard)) 
						huxi = changeHuXi(tempOpCardList, opCards, huxi, CardUtil.checkHongCard(mingCard) ? 7 : 5, mingCard);
				}
			}
			if (hu) {
				if (huxi == 2 && (this.player.getRoom().config.getInt(Config.ROOM_CONFIG_WANFA) != 0 ) && !isZhuanWan) {
					List<OpCard> allOpCard = new ArrayList<>();
					allOpCard.addAll(opCardList);
					allOpCard.addAll(opCards);
					if (CardUtil.checkManYuanHua(allOpCard)) {
						player.huXi = huxi;
						int caclWin = player.getRoom().caclWin(player, player.seat == player.getRoom().draw);
						if (allHuXi < caclWin) {
							allHuXi = caclWin;
							maxHuXi = huxi;
							this.maxOpCard.clear();
							this.maxOpCard.addAll(opCards);
						}
					}
				}else {
					player.handCard.clear();
					for (OpCard opcard : opCards) {
						player.handCard.push(opcard);
					}
					if (huxi >= 10) {
						player.huXi = huxi;
						int caclWin = player.getRoom().caclWin(player, player.seat == player.getRoom().draw);
						if (allHuXi < caclWin) {
							allHuXi = caclWin;
							maxHuXi = huxi;
							this.maxOpCard.clear();
							this.maxOpCard.addAll(opCards);
						}
					}
				}
			}
		}
		return this.maxOpCard.size() > 0;
	}


	private boolean pair(List<Integer> cards) {
		if (cards.size() == 2) {
			if (CardUtil.cardNum(cards.get(0), cards) == 2) {
				return true;
			}
		}
		return false;
	}

	private void removeOpCard(List<Integer> cards, OpCard opCard) {
		if (opCard != null) {
			
		}
		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);
		}

	}

	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);
		kan(card, opCardList, tempList);
		if (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, tempList) >= 2) {
				OpCard opCard = new OpCard();
				opCard.card1 = card;
				opCard.card2 = card;
				if (card%100 == 2 || card%100 == 7 || card%100 == 10) {
					opCard.huXi = 2;
				}
				opCard.type = RuleWeight.TYPE_JIANG;
				list.add(opCard);
			}
		}
	}

	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;
		OpCard opCard = new OpCard(RuleWeight.TYPE_CHOW, opCardList.get(0), opCardList.get(1), opCardList.get(2), huXi);
		return opCard;
	}

	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 type = card == this.addCard ? RuleWeight.TYPE_PONG : RuleWeight.TYPE_KAN;
			int huxi = CardUtil.getCardGroupHuxi(card, type, this.opCardList);
			OpCard opCard = new OpCard(type, opCardList.get(0), opCardList.get(1), opCardList.get(2), huxi);
			list.add(opCard);
		}
	}

	public static void main(String[] args) throws ClassNotFoundException, IOException {
		List<Integer> list = new ArrayList<>();
		String str = "107, 110, 110, 110";
		for (String card : str.split(", ")) {
			list.add(Integer.parseInt(card));
		}
		WinCard winCard2 = new WinCard(list, 107, 10, true, new ArrayList<OpCard>(), null);

		System.out.println(winCard2.checkHu());
		System.out.println(winCard2.maxOpCardToString()); 
		System.out.println(winCard2.maxHuXi);

	}

	public String maxOpCardToString() {
		StringBuffer sb = new StringBuffer();
		for (OpCard opCard : maxOpCard) {
			if (opCard.type == RuleWeight.TYPE_JIANG) {
				sb.append("jiangcard:" + opCard.card1 + " ");
				sb.append(opCard.card2);
				sb.append(",huxi=" + opCard.huXi + " | ");
			} else {
				sb.append(opCard.card1 + " ");
				sb.append(opCard.card2 + " ");
				sb.append(opCard.card3);
				sb.append(",huxi=" + opCard.huXi + " | ");
			}
		}
		return sb.toString();
	}

	public WinCard(List<Integer> cardInhand, int addCard, int huxi, boolean isJiang, List<OpCard> opCardList, EXPlayer owner) {
		this.opCardStack = new Stack<>();
		this.lastOpCard = new ArrayList<>();
		this.cardList = new ArrayList<Integer>();
		this.maxOpCard = new ArrayList<>();
		this.opCardList = new ArrayList<>();
		this.cardhand = new ArrayList<>();
		this.cardList.addAll(cardInhand);
		this.cardhand.addAll(cardInhand);
		this.opCardList.addAll(opCardList);
		this.player = owner;
		if (addCard > 0) {
			this.cardList.add(addCard);
		}
		Collections.sort(this.cardList);
		this.isJiang = isJiang;
		this.addCard = addCard;
		this.huxi = huxi;
	}

}
