import java.awt.Color;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;


import javax.imageio.ImageIO;

class Card{
	
	int id;
	String shape;
	String color;
	String infill;
	int shapeCount;
	byte[] fileBytes;
	Point position;
	
	Card(int id, String shape, String color, String infill, int shapeCount) throws Exception{
		this.id = id;
		this.shape = shape;
		this.color = color;
		this.infill = infill;
		this.shapeCount = shapeCount;
		this.fileBytes = Files.readAllBytes(Paths.get(id+".png"));
	}
}

public class SetBeater {

	public static void main(String[] args) throws Exception {
		
		Card[] allCards = new Card[81];
		allCards[0] = new Card(1, "squiggle", "red", "solid", 1);
		allCards[1] = new Card(2, "squiggle", "red", "solid", 2);
		allCards[2] = new Card(3, "squiggle", "red", "solid", 3);
		allCards[3] = new Card(4, "squiggle", "purple", "solid", 1);
		allCards[4] = new Card(5, "squiggle", "purple", "solid", 2);
		allCards[5] = new Card(6, "squiggle", "purple", "solid", 3);
		allCards[6] = new Card(7, "squiggle", "green", "solid", 1);
		allCards[7] = new Card(8, "squiggle", "green", "solid", 2);
		allCards[8] = new Card(9, "squiggle", "green", "solid", 3);
		
		allCards[9] = new Card(10, "diamond", "red", "solid", 1);
		allCards[10] = new Card(11, "diamond", "red", "solid", 2);
		allCards[11] = new Card(12, "diamond", "red", "solid", 3);
		allCards[12] = new Card(13, "diamond", "purple", "solid", 1);
		allCards[13] = new Card(14, "diamond", "purple", "solid", 2);
		allCards[14] = new Card(15, "diamond", "purple", "solid", 3);
		allCards[15] = new Card(16, "diamond", "green", "solid", 1);
		allCards[16] = new Card(17, "diamond", "green", "solid", 2);
		allCards[17] = new Card(18, "diamond", "green", "solid", 3);
		
		allCards[18] = new Card(19, "oval", "red", "solid", 1);
		allCards[19] = new Card(20, "oval", "red", "solid", 2);
		allCards[20] = new Card(21, "oval", "red", "solid", 3);
		allCards[21] = new Card(22, "oval", "purple", "solid", 1);
		allCards[22] = new Card(23, "oval", "purple", "solid", 2);
		allCards[23] = new Card(24, "oval", "purple", "solid", 3);
		allCards[24] = new Card(25, "oval", "green", "solid", 1);
		allCards[25] = new Card(26, "oval", "green", "solid", 2);
		allCards[26] = new Card(27, "oval", "green", "solid", 3);
		
		allCards[27] = new Card(28, "squiggle", "red", "stripe", 1);
		allCards[28] = new Card(29, "squiggle", "red", "stripe", 2);
		allCards[29] = new Card(30, "squiggle", "red", "stripe", 3);
		allCards[30] = new Card(31, "squiggle", "purple", "stripe", 1);
		allCards[31] = new Card(32, "squiggle", "purple", "stripe", 2);
		allCards[32] = new Card(33, "squiggle", "purple", "stripe", 3);
		allCards[33] = new Card(34, "squiggle", "green", "stripe", 1);
		allCards[34] = new Card(35, "squiggle", "green", "stripe", 2);
		allCards[35] = new Card(36, "squiggle", "green", "stripe", 3);
		
		allCards[36] = new Card(37, "diamond", "red", "stripe", 1);
		allCards[37] = new Card(38, "diamond", "red", "stripe", 2);
		allCards[38] = new Card(39, "diamond", "red", "stripe", 3);
		allCards[39] = new Card(40, "diamond", "purple", "stripe", 1);
		allCards[40] = new Card(41, "diamond", "purple", "stripe", 2);
		allCards[41] = new Card(42, "diamond", "purple", "stripe", 3);
		allCards[42] = new Card(43, "diamond", "green", "stripe", 1);
		allCards[43] = new Card(44, "diamond", "green", "stripe", 2);
		allCards[44] = new Card(45, "diamond", "green", "stripe", 3);
		
		allCards[45] = new Card(46, "oval", "red", "stripe", 1);
		allCards[46] = new Card(47, "oval", "red", "stripe", 2);
		allCards[47] = new Card(48, "oval", "red", "stripe", 3);
		allCards[48] = new Card(49, "oval", "purple", "stripe", 1);
		allCards[49] = new Card(50, "oval", "purple", "stripe", 2);
		allCards[50] = new Card(51, "oval", "purple", "stripe", 3);
		allCards[51] = new Card(52, "oval", "green", "stripe", 1);
		allCards[52] = new Card(53, "oval", "green", "stripe", 2);
		allCards[53] = new Card(54, "oval", "green", "stripe", 3);
		
		allCards[54] = new Card(55, "squiggle", "red", "empty", 1);
		allCards[55] = new Card(56, "squiggle", "red", "empty", 2);
		allCards[56] = new Card(57, "squiggle", "red", "empty", 3);
		allCards[57] = new Card(58, "squiggle", "purple", "empty", 1);
		allCards[58] = new Card(59, "squiggle", "purple", "empty", 2);
		allCards[59] = new Card(60, "squiggle", "purple", "empty", 3);
		allCards[60] = new Card(61, "squiggle", "green", "empty", 1);
		allCards[61] = new Card(62, "squiggle", "green", "empty", 2);
		allCards[62] = new Card(63, "squiggle", "green", "empty", 3);
		
		allCards[63] = new Card(64, "diamond", "red", "empty", 1);
		allCards[64] = new Card(65, "diamond", "red", "empty", 2);
		allCards[65] = new Card(66, "diamond", "red", "empty", 3);
		allCards[66] = new Card(67, "diamond", "purple", "empty", 1);
		allCards[67] = new Card(68, "diamond", "purple", "empty", 2);
		allCards[68] = new Card(69, "diamond", "purple", "empty", 3);
		allCards[69] = new Card(70, "diamond", "green", "empty", 1);
		allCards[70] = new Card(71, "diamond", "green", "empty", 2);
		allCards[71] = new Card(72, "diamond", "green", "empty", 3);
		
		allCards[72] = new Card(73, "oval", "red", "empty", 1);
		allCards[73] = new Card(74, "oval", "red", "empty", 2);
		allCards[74] = new Card(75, "oval", "red", "empty", 3);
		allCards[75] = new Card(76, "oval", "purple", "empty", 1);
		allCards[76] = new Card(77, "oval", "purple", "empty", 2);
		allCards[77] = new Card(78, "oval", "purple", "empty", 3);
		allCards[78] = new Card(79, "oval", "green", "empty", 1);
		allCards[79] = new Card(80, "oval", "green", "empty", 2);
		allCards[80] = new Card(81, "oval", "green", "empty", 3);
		
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();  
		GraphicsDevice[] screens = ge.getScreenDevices();  
		
		Rectangle screenBounds = screens[1].getDefaultConfiguration().getBounds();
		BufferedImage image = new Robot().createScreenCapture(screenBounds);
		
		int rows = 3, cols = 4;
		BufferedImage[][] cards = new BufferedImage[rows][cols];
		cards[0][0] = image.getSubimage(245, 499, 95, 62);
		cards[0][1] = image.getSubimage(394, 499, 95, 62);
		cards[0][2] = image.getSubimage(543, 499, 95, 62);
		cards[0][3] = image.getSubimage(693, 499, 95, 62);
		
		cards[1][0] = image.getSubimage(245, 588, 95, 62);
		cards[1][1] = image.getSubimage(394, 588, 95, 62);
		cards[1][2] = image.getSubimage(543, 588, 95, 62);
		cards[1][3] = image.getSubimage(693, 588, 95, 62);
		
		cards[2][0] = image.getSubimage(245, 677, 95, 62);
		cards[2][1] = image.getSubimage(394, 677, 95, 62);
		cards[2][2] = image.getSubimage(543, 677, 95, 62);
		cards[2][3] = image.getSubimage(693, 677, 95, 62);
		
		ArrayList<Byte> [][] cardBytes = new ArrayList[rows][cols];
		for(int i=0; i<rows; i++)
			for(int j=0; j<cols; j++){
				cardBytes[i][j] = new ArrayList<Byte>();
				ImageIO.write(cards[i][j], "png", new File("card-"+i+","+j+".png"));
				byte[] bytes = Files.readAllBytes(Paths.get("card-"+i+","+j+".png"));
				for(int k=0; k<bytes.length; k++)
					cardBytes[i][j].add(bytes[k]);
			}
		
		int checkBoxSides = 12;
		Point checkBoxes[][] = new Point[rows][cols];
		for(int i=0; i<rows; i++)
			for(int j=0; j<cols; j++)
				checkBoxes[i][j] = new Point();
		
		int xOffset = -1600;
		checkBoxes[0][0].setLocation(xOffset+292,575);
		checkBoxes[0][1].setLocation(xOffset+441,575);
		checkBoxes[0][2].setLocation(xOffset+591,575);
		checkBoxes[0][3].setLocation(xOffset+741,575);
		
		checkBoxes[1][0].setLocation(xOffset+292,663);
		checkBoxes[1][1].setLocation(xOffset+441,663);
		checkBoxes[1][2].setLocation(xOffset+591,663);
		checkBoxes[1][3].setLocation(xOffset+741,663);
		
		checkBoxes[2][0].setLocation(xOffset+292,752);
		checkBoxes[2][1].setLocation(xOffset+441,752);
		checkBoxes[2][2].setLocation(xOffset+591,752);
		checkBoxes[2][3].setLocation(xOffset+741,752);
		
		ArrayList<Card> dealtCards = new ArrayList<Card>();
		for(int i=0; i<rows; i++)
			for(int j=0; j<cols; j++)
				for(int k=0; k<allCards.length; k++)
					if (cardBytes[i][j].size() == allCards[k].fileBytes.length){
						//System.out.println("Same length detected");
						boolean matched = true;
						for(int l=0; l<allCards[k].fileBytes.length; l++)
							if (cardBytes[i][j].get(l) != allCards[k].fileBytes[l]){
								matched = false;
								break;
							}

						if (matched){
							allCards[k].position = new Point(i,j);
							dealtCards.add(allCards[k]);
						}
					}
		
		ArrayList<ArrayList<Card>> setsFound;
		setsFound = new ArrayList<ArrayList<Card>>();
		
		for(int i=0; i<dealtCards.size(); i++)
			for(int j=i+1; j<dealtCards.size(); j++)
				for(int k=j+1; k<dealtCards.size(); k++){
					boolean sameColor = (dealtCards.get(i).color == dealtCards.get(j).color && dealtCards.get(i).color == dealtCards.get(k).color && dealtCards.get(j).color == dealtCards.get(k).color);
					boolean sameInfill = (dealtCards.get(i).infill == dealtCards.get(j).infill && dealtCards.get(i).infill == dealtCards.get(k).infill && dealtCards.get(j).infill == dealtCards.get(k).infill);
					boolean sameShape = (dealtCards.get(i).shape == dealtCards.get(j).shape && dealtCards.get(i).shape == dealtCards.get(k).shape && dealtCards.get(j).shape == dealtCards.get(k).shape);
					boolean sameShapeCount = (dealtCards.get(i).shapeCount == dealtCards.get(j).shapeCount && dealtCards.get(i).shapeCount == dealtCards.get(k).shapeCount && dealtCards.get(j).shapeCount == dealtCards.get(k).shapeCount);
					
					int sameTotal = 0;
					if (sameColor)
						sameTotal++;
					if (sameInfill)
						sameTotal++;
					if (sameShape)
						sameTotal++;
					if (sameShapeCount)
						sameTotal++;
					
					boolean allDifferentColor = (dealtCards.get(i).color != dealtCards.get(j).color && dealtCards.get(i).color != dealtCards.get(k).color && dealtCards.get(j).color != dealtCards.get(k).color);
					boolean allDifferentInfill = (dealtCards.get(i).infill != dealtCards.get(j).infill && dealtCards.get(i).infill != dealtCards.get(k).infill && dealtCards.get(j).infill != dealtCards.get(k).infill);
					boolean allDifferentShape = (dealtCards.get(i).shape != dealtCards.get(j).shape && dealtCards.get(i).shape != dealtCards.get(k).shape && dealtCards.get(j).shape != dealtCards.get(k).shape);
					boolean allDifferentShapeCount = (dealtCards.get(i).shapeCount != dealtCards.get(j).shapeCount && dealtCards.get(i).shapeCount != dealtCards.get(k).shapeCount && dealtCards.get(j).shapeCount != dealtCards.get(k).shapeCount);
					
					int allDifferentTotal = 0;
					if (allDifferentColor)
						allDifferentTotal++;
					if (allDifferentInfill)
						allDifferentTotal++;
					if (allDifferentShape)
						allDifferentTotal++;
					if (allDifferentShapeCount)
						allDifferentTotal++;
					
					boolean setFound = false;
					
					if (allDifferentTotal == 4)
						setFound = true;
					else if (allDifferentTotal == 3 && sameTotal == 1)
						setFound = true;
					else if (allDifferentTotal == 2 && sameTotal == 2)
						setFound = true;
					/*
					if (sameShape && sameColor && allDifferentInfill && allDifferentShapeCount)
						setFound = true;
					else if (sameShape && allDifferentColor && sameInfill && allDifferentShapeCount)
						setFound = true;
					else if (sameShape && allDifferentColor && allDifferentInfill && sameShapeCount)
						setFound = true;
					else if (sameShape && allDifferentColor && allDifferentInfill && allDifferentShapeCount)
						setFound = true;
					else if (allDifferentShape && sameColor && allDifferentInfill && allDifferentShapeCount)
						setFound = true;
					else if (allDifferentShape && allDifferentColor && sameInfill && allDifferentShapeCount)
						setFound = true;
					else if (allDifferentShape && allDifferentColor && allDifferentInfill && sameShapeCount)
						setFound = true;
					else if (allDifferentShape && allDifferentColor && allDifferentInfill && allDifferentShapeCount)
						setFound = true;
					*/
					if (setFound == true){
						ArrayList<Card> set = new ArrayList<Card>();
						set.add(dealtCards.get(i));
						set.add(dealtCards.get(j));
						set.add(dealtCards.get(k));
					
						setsFound.add(set);
					}
				}
		System.out.println(setsFound.size());
		
		Point okButtonShort = new Point(xOffset+926,182);
		Point okButtonLong = new Point(xOffset+926,213);
		boolean clickedOkButtonSimple = false;
		
		Robot robot = new Robot();
		int checked = 0;
		
		int mouseActionDelay = 500;
		
		for(int i=0; i<setsFound.size(); i++){
			ArrayList<Card> cardSet = setsFound.get(i);
			
			for(int j=0; j<cardSet.size(); j++){
				robot.mouseMove((int) checkBoxes[(int) cardSet.get(j).position.getX()][(int) cardSet.get(j).position.getY()].getX(), (int) checkBoxes[(int) cardSet.get(j).position.getX()][(int) cardSet.get(j).position.getY()].getY());
				robot.mousePress(InputEvent.BUTTON1_MASK);
				robot.mouseRelease(InputEvent.BUTTON1_MASK);
				checked++;
				Thread.sleep(mouseActionDelay);
				
				if (checked == 3){
					if (clickedOkButtonSimple == false || mouseActionDelay >= 250){
						robot.mouseMove((int) okButtonShort.getX(), (int) okButtonShort.getY());
						clickedOkButtonSimple = true;
					}
					else
						robot.mouseMove((int) okButtonLong.getX(), (int) okButtonLong.getY());
				
					robot.mousePress(InputEvent.BUTTON1_MASK);
					robot.mouseRelease(InputEvent.BUTTON1_MASK);
					Thread.sleep(mouseActionDelay);
					checked = 0;
				}
			}
		}
	}
	
	static void downloadAllSetCards() throws Exception{
		for(int i=1; i<=3*3*3*3; i++){
			String filename = "";
			if (i < 10)
				filename = "0"+i;
			else
				filename = i+"";
			
			filename += ".gif";
			URL website = new URL("http://www.puzzles.setgame.com/images/setcards/small/"+filename);
			ReadableByteChannel rbc = Channels.newChannel(website.openStream());
			FileOutputStream fos = new FileOutputStream(i+".gif");
			fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
		}
	}
	
	void convertCards() throws Exception{
		for(int i=1; i<82; i++){
			BufferedImage bufferedImage = ImageIO.read(new File(i+".gif"));
			BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
			newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
			ImageIO.write(newBufferedImage, "png", new File(i+".png"));
		}
	}
	
}
