public class BenchmarkNodeID {

    private int id;

    public BenchmarkNodeID(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public boolean isMaster() {
        return id == 1;

    }

} public class ResultHandler {

	private static List<ResultHandler> client_results =  new CopyOnWriteArrayList<ResultHandler>();

	private Map<String, String> bechmark_info = null;

	private int testsamples = 100;

	private String test_name;


	/**
	 * results -> for each operation store the result in(currentTime:result) *
	 */
	private HashMap<String, ArrayList<Pair<Long, Long>>> time_results;

	/**
	 * results -> for each operation store data as a list of Objects *
	 */
	private HashMap<String, ArrayList<ArrayList<Object>>> data_results;

	//Store information in 2 maps, allowing for example, the storage of several data per event,
	// like the time and place of a racer.
	private HashMap<String, HashMap<String, ArrayList<Object>>> data;

	//Store information in 2 maps, allowing for example, the storage of several data per event,
	// like the time and place of a racer.
	private HashMap<String, ArrayList<Pair<String, ArrayList<Object>>>> unstructured_data;


	//Data header to when printing data, should be on the printing method.
	private TreeMap<String, ArrayList<String>> dataHeader;

	//result events by type -> for each operation store the event occurrence like this (BankOperation,deposit,3)
	private HashMap<String, HashMap<String, Long>> events;

	//Abstract result set -> to store results od some kind
	private HashMap<String, Object> resulSet;

	/**
	 * @param run_data_divisions the division in the data by runs. If -1 all will be inserted un the same run;
	 */
	public ResultHandler(String name, int run_data_divisions) {

		this.test_name = name;
		testsamples = run_data_divisions;

		time_results = new HashMap<String, ArrayList<Pair<Long, Long>>>();

		events = new HashMap<String, HashMap<String, Long>>();

		data = new HashMap<String, HashMap<String, ArrayList<Object>>>();

		unstructured_data = new HashMap<String, ArrayList<Pair<String, ArrayList<Object>>>>();

		dataHeader = new TreeMap<String, ArrayList<String>>();

		resulSet = new HashMap<String, Object>();

	//	synchronized (client_results){
			client_results.add(this);
	//	}

	}

	/**
	 * **LOG OPERATIONS****
	 */

	public void logResult(String operation, long result) {

		Pair<Long, Long> resultPair = new Pair<Long, Long>(System.currentTimeMillis(), result);
		if (!time_results.containsKey(operation)) {
			time_results.put(operation, new ArrayList<Pair<Long, Long>>());
		}
		time_results.get(operation).add(resultPair);
	}

	public void countEvent(String eventType, String event, long number) {

		if (!events.containsKey(eventType)) {
			HashMap<String, Long> new_events = new HashMap<String, Long>();
			new_events.put(event, number);
			events.put(eventType, new_events);
		} else {
			if (!events.get(eventType).containsKey(event)) {
				events.get(eventType).put(event, number);
			} else {
				long count = events.get(eventType).get(event) + number;
				events.get(eventType).put(event, count);
			}
		}

	}

	public synchronized void concurrent_countEvent(String eventType, String event, long number) {

		if (!events.containsKey(eventType)) {
			HashMap<String, Long> new_events = new HashMap<String, Long>();
			new_events.put(event, number);
			events.put(eventType, new_events);
		} else {
			if (!events.get(eventType).containsKey(event)) {
				events.get(eventType).put(event, number);
			} else {
				long count = events.get(eventType).get(event) + number;
				events.get(eventType).put(event, count);
			}
		}

	}

	public void recordData(String eventType, String event, List<Object> record_data) {

		if (!data.containsKey(eventType)) {
			HashMap<String, ArrayList<Object>> data_slot = new HashMap<String, ArrayList<Object>>();
			ArrayList<Object> data_list = new ArrayList<Object>(record_data);
			data_slot.put(event, data_list);
			data.put(eventType, data_slot);
		} else {
			ArrayList<Object> data_list = new ArrayList<Object>(record_data);
			data.get(eventType).put(event, data_list);
		}

	}

	public void record_unstructured_data(String eventType, String event, List<Object> record_data) {

		if (!unstructured_data.containsKey(eventType)) {
			ArrayList<Pair<String, ArrayList<Object>>> data_slot = new ArrayList<Pair<String, ArrayList<Object>>>();
			ArrayList<Object> data_list = new ArrayList<Object>(record_data);
			data_slot.add(new Pair<String, ArrayList<Object>>(event, data_list));
			unstructured_data.put(eventType, data_slot);
		} else {
			ArrayList<Object> data_list = new ArrayList<Object>(record_data);
			unstructured_data.get(eventType).add((new Pair<String, ArrayList<Object>>(event, data_list)));
		}

	}

	public HashMap<String, Object> getResulSet() {
		return resulSet;
	}

	public void setResulSet(HashMap<String, Object> resulSet) {
		this.resulSet = resulSet;
	}

	public void setBechmark_info(Map<String, String> bechmark_info) {
		this.bechmark_info = bechmark_info;
	}

	public Map<String, String> getBechmark_info() {
		return bechmark_info;
	}

	public HashMap<String, ArrayList<Pair<Long, Long>>> getTime_results() {
		return time_results;
	}

	/**
	 * UTILITIES***
	 */

	public void cleanResults() {
		time_results.clear();
		data.clear();
		events.clear();
		System.gc();

	}

	public void setDataHeader(String EventType, ArrayList<String> dataHeader) {
		this.dataHeader.put(EventType, dataHeader);

	}

	public void addResults(ResultHandler other_results) {

		Map<String, ArrayList<Pair<Long, Long>>> new_results = other_results.time_results;

		for (String event_name : new_results.keySet()) {
			if (!this.time_results.containsKey(event_name)) {
				this.time_results.put(event_name, new_results.get(event_name));
			} else {
				for (Pair<Long, Long> l : new_results.get(event_name)) {
					this.time_results.get(event_name).add(l);
				}
			}
		}

		Map<String, HashMap<String, Long>> new_events = other_results.events;

		for (String event_name : new_events.keySet()) {
			if (!this.events.containsKey(event_name)) {
				this.events.put(event_name, new_events.get(event_name));
			} else {
				HashMap<String, Long> new_event_count = new_events.get(event_name);
				HashMap<String, Long> this_event_count = this.events.get(event_name);
				for (String event_count_name : new_event_count.keySet()) {
					if (this_event_count.containsKey(event_count_name)) {
						this_event_count.put(event_count_name, this_event_count.get(event_count_name) + new_event_count.get(event_count_name));
					} else {
						this_event_count.put(event_count_name, new_event_count.get(event_count_name));
					}
				}
			}
		}

		HashMap<String, ArrayList<Pair<String, ArrayList<Object>>>> un_data = other_results.unstructured_data;

		for (Map.Entry<String, ArrayList<Pair<String, ArrayList<Object>>>> data_entry : un_data.entrySet()) {

			String event_type = data_entry.getKey();
			ArrayList<Pair<String, ArrayList<Object>>> data_info = data_entry.getValue();

			if (!this.unstructured_data.containsKey(event_type)) {
				unstructured_data.put(event_type, data_info);
			} else {
				for (Pair<String, ArrayList<Object>> event : data_info) {
					unstructured_data.get(event_type).add(event);
				}
			}
		}
	}

	/**
	 * OUTPUT
	 **/

	public void listDataToSOutput() {

		System.out.println("\n\n------- RESULTS FOR: " + test_name + "-------");
		System.out.println("--runs: " + testsamples);
		for (String dataOperation : time_results.keySet()) {
			System.out.println("OPERATION: " + dataOperation);
			ArrayList<Pair<Long, Long>> result_data = time_results.get(dataOperation);
			boolean do_multipleruns = testsamples >= 0;


			int total_amount = 0;
			int currrent_amount = 0;
			int current_run = 0;
			int run = 0;
			ArrayList<Long> run_result = new ArrayList<Long>();
			for (Pair<Long, Long> res : result_data) {

				run_result.add(res.right);
				total_amount += res.right;
				currrent_amount += res.right;
				current_run += 1;

				if (do_multipleruns && current_run == testsamples) {
					System.out.println("--RESULTS FOR RUN " + run + "");
					double average = (currrent_amount * 1.0d) / (testsamples * 1.0d);
					System.out.println("Average: " + average);
					double variance = 0.0;
					long aux = 0;
					for (Long run_res : run_result) {
						aux += Math.pow((run_res - average), 2);
					}
					variance = aux * (1d / (run_result.size() - 1d));
					System.out.println("Variance: " + variance);

					run++;
					currrent_amount = 0;
					current_run = 0;


					run_result = new ArrayList<Long>();
				}
			}
			if (!result_data.isEmpty()) {

				System.out.println("----TOTAL RESULTS:----");
				double average = (total_amount * 1.0d) / (result_data.size() * 1.0d);
				System.out.println("Average: " + average);
				double variance = 0.0;
				long aux = 0;
				for (Pair<Long, Long> run_res : result_data) {
					aux += Math.pow((run_res.right - average), 2);
				}
				variance = aux * (1d / (result_data.size() - 1d));
				System.out.println("Variance: " + variance + "\n\n");
			}
		}
		if (!events.isEmpty()) {
			System.out.println("****EVENT COUNT****");
			for (String eventType : events.keySet()) {
				System.out.println("+EVENT TYPE: " + eventType);
				for (String event : events.get(eventType).keySet()) {
					System.out.println("\t>>" + event + " : " + events.get(eventType).get(event));
				}
			}

		}
		if (!data.isEmpty()) {
			System.out.println("\n\n***DATA RECORDS ARE NOT SHOWN IN THIS METHOD - USE SAVE TO FILE OPTIONS****\n");
		}

	}

	public void listDatatoFiles(String folder_name, String perfix, boolean doMultiple) {

		int unknown = 0;

		System.out.println("\n\n-------WRITING RESULTS FOR: " + test_name + "-------");
		File enclosing_folder = new File(folder_name);
		System.out.println("OUTPUT PATH: " + enclosing_folder.getAbsolutePath());
		if (!enclosing_folder.exists()) {
			System.out.println("RESULT DEFINED PARENT FOLDER DOES NOT EXISTS - CREATING");
			boolean created = enclosing_folder.mkdir();
			if (!created) {
				System.out.println("RESULT DEFINED PARENT FOLDER DOES NOT EXISTS AND CANT BE CREATED - TRYING ENCLOSING FOLDER");
				enclosing_folder = enclosing_folder.getParentFile();
			}

		} else if (!enclosing_folder.isDirectory()) {
			enclosing_folder = enclosing_folder.getParentFile();
			System.out.println("NOT A FOLDER: ENCLOSING FOLDER USED -> " + enclosing_folder);
		}

		GregorianCalendar date = new GregorianCalendar();
		String suffix = date.get(GregorianCalendar.YEAR) + "_" + (date.get(GregorianCalendar.MONTH) + 1) + "_" + date.get(GregorianCalendar.DAY_OF_MONTH) + "_" + date.get(GregorianCalendar.HOUR_OF_DAY) + "_" + date.get(GregorianCalendar.MINUTE) + "";

		File folder = new File(enclosing_folder.getAbsolutePath() + "/" + test_name + suffix);

		if (!folder.exists()) {
			boolean created = folder.mkdir();
			if (!created) {
				System.out.println("RESULT FOLDER DOES NOT EXISTS AND CANT BE CREATED - USING EXECUTION FOLDER");
				File exe_folder = new File("./Results" + "/" + test_name + suffix);
				if (!exe_folder.exists()) {
					created = exe_folder.mkdir();
					if (!created) {
						System.out.println("EXECUTION FOLDER CANT BE USED, LEAVING...");
						return;
					} else {
						folder = exe_folder;
					}
				}
			}
		}
		System.out.println("OUTPUT FOLDER: " + folder.getName());

		for (String dataOperation : time_results.keySet()) {


			ArrayList<Pair<Long, Long>> result_data = time_results.get(dataOperation);

			if (dataOperation.trim().equals("")) {

				dataOperation = (unknown == 0) ? "UNKNOWN" : "UNKNOWN_" + unknown;
				unknown++;
			}

			boolean do_multiple_runs = (!(testsamples < 0 && doMultiple));

			int current_run = 0;
			int run = 0;
			File operation_results_file = new File(folder.getPath() + "/" + dataOperation);


			try {
				operation_results_file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			}

			FileOutputStream out = null;
			BufferedOutputStream stream = null;

			try {
				out = new FileOutputStream(operation_results_file);
				stream = new BufferedOutputStream(out);

			} catch (Exception e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			}


			try {
				if (!do_multiple_runs) {
					stream.write(("results , time  \n").getBytes());
				} else {
					stream.write(("results , time , run\n").getBytes());

				}

			} catch (IOException e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			}

			resultComparator comparator = new resultComparator();
			Collections.sort(result_data, comparator);

			int length = result_data.size();
			for (int z = 0; z < length; z++) {

				Pair<Long, Long> res = result_data.get(z);

				current_run += 1;

				String result_line = res.right + " , " + res.left + "";
				if (do_multiple_runs) {
					result_line = result_line + " , " + run;
				}
				result_line = result_line + "\n";

				if (do_multiple_runs && current_run == testsamples) {
					run++;
				}
				try {
					stream.write(result_line.getBytes());

				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}
			}

			try {
				stream.flush();
				stream.close();
			} catch (IOException e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			} finally {
				try {
					out.close();
				} catch (IOException ex) {
					Logger.getLogger(ResultHandler.class.getName()).log(Level.SEVERE, null, ex);
				}
			}


		}
		if (!events.isEmpty()) {
			System.out.println("****WRITING EVENT COUNT****");


			for (String eventType : events.keySet()) {
				File event_results_file = new File(folder.getPath() + "/" + eventType);
				FileOutputStream out = null;
				BufferedOutputStream stream = null;
				try {
					out = new FileOutputStream(event_results_file);
					stream = new BufferedOutputStream(out);

				} catch (FileNotFoundException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}


				System.out.println("+EVENT TYPE: " + eventType);
				for (String event : events.get(eventType).keySet()) {
					// System.out.println("\t>>" + event + " : " + events.get(eventType).get(event));
					try {
						out.write((event + " , " + events.get(eventType).get(event) + "\n").getBytes());
					} catch (IOException e) {
						e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
					}
				}
				try {
					stream.flush();
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				} finally {
					try {
						out.close();
					} catch (IOException ex) {
						Logger.getLogger(ResultHandler.class.getName()).log(Level.SEVERE, null, ex);
					}


				}

			}

		}


		if (!unstructured_data.isEmpty()) {
			System.out.println("****WRITING UNSTRUCTURED DATA COUNT****");


			for (String eventType : unstructured_data.keySet()) {
				File event_results_file = new File(folder.getPath() + "/" + eventType);
				FileOutputStream out = null;
				BufferedOutputStream stream = null;
				try {
					out = new FileOutputStream(event_results_file);
					stream = new BufferedOutputStream(out);

				} catch (FileNotFoundException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}


				System.out.println("+UNSTRUCTURED DATA EVENT TYPE: " + eventType);
				int i = 0;
				if (dataHeader.get(eventType) != null) {

					try {

						//    dataHeader.put(eventType, new ArrayList<String>());


						for (String header_name : dataHeader.get(eventType)) {
							if (i != 0)
								out.write(" , ".getBytes());

							out.write(header_name.getBytes());
							i++;
						}
						out.write("\n".getBytes());
					} catch (IOException e) {
						e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
					}
				}

				for (ArrayList<Pair<String, ArrayList<Object>>> pairs : unstructured_data.values()) {


					for (Pair<String, ArrayList<Object>> pair : pairs) {

						try {
							out.write((pair.left).getBytes());
							for (Object o : pair.right) {
								out.write((" , " + o.toString()).getBytes());
							}
							out.write("\n".getBytes());

						} catch (IOException e) {
							e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
						}


					}

				}


				try {
					stream.flush();
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				} finally {
					try {
						out.close();
					} catch (IOException ex) {
						Logger.getLogger(ResultHandler.class.getName()).log(Level.SEVERE, null, ex);
					}


				}

			}

		}


		if (!data.isEmpty()) {
			System.out.println("****WRITING DATA COUNT****");


			for (String eventType : data.keySet()) {
				File event_results_file = new File(folder.getPath() + "/" + eventType);
				FileOutputStream out = null;
				BufferedOutputStream stream = null;
				try {
					out = new FileOutputStream(event_results_file);
					stream = new BufferedOutputStream(out);

				} catch (FileNotFoundException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}


				System.out.println("+DATA EVENT TYPE: " + eventType);
				int i = 0;
				try {

					if (dataHeader.get(eventType) == null) {
						dataHeader.put(eventType, new ArrayList<String>());
					}

					for (String header_name : dataHeader.get(eventType)) {
						if (i != 0)
							out.write(" , ".getBytes());

						out.write(header_name.getBytes());
						i++;
					}
					out.write("\n".getBytes());
				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}


				for (String event : data.get(eventType).keySet()) {


//					if (eventType.equals("BUYING RESULTS")) {
//
//
//						int item_id = Integer.parseInt(event);
//						if (item_id < 100) {
//
//							List<Object> list = data.get(eventType).get(event);
//						//	if ((Integer)list.get(2) != 0)
//								System.out.println(item_id + " -.- " + list.get(2));
//						}
//
//
//					}

					try {
						out.write((event).getBytes());
						for (Object o : data.get(eventType).get(event)) {
							out.write((" , " + o.toString()).getBytes());
						}
						out.write("\n".getBytes());

					} catch (IOException e) {
						e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
					}
				}


				try {
					stream.flush();
					stream.close();
				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				} finally {
					try {
						out.close();
					} catch (IOException ex) {
						Logger.getLogger(ResultHandler.class.getName()).log(Level.SEVERE, null, ex);
					}


				}

			}

		}

		if (bechmark_info != null && !bechmark_info.isEmpty()) {
			File event_results_file = new File(folder.getPath() + "/" + "BENCHMARK_INFO");
			FileOutputStream out = null;
			BufferedOutputStream stream = null;
			try {
				out = new FileOutputStream(event_results_file);
				stream = new BufferedOutputStream(out);

			} catch (FileNotFoundException e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			}

			for (String field : bechmark_info.keySet()) {
				// System.out.println("\t>>" + event + " : " + events.get(eventType).get(event));
				try {
					out.write((field + " - " + bechmark_info.get(field) + "\n").getBytes());
				} catch (IOException e) {
					e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
				}
			}
			try {
				stream.flush();
				stream.close();
			} catch (IOException e) {
				e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
			} finally {
				try {
					out.close();
				} catch (IOException ex) {
					Logger.getLogger(ResultHandler.class.getName()).log(Level.SEVERE, null, ex);
				}


			}


		}

	}

	class resultComparator implements Comparator {

		public int compare(Object o1, Object o2) {

			if (!(o1 instanceof Pair) || !(o2 instanceof Pair))
				return 0;

			Pair<Long, Long> p1 = (Pair<Long, Long>) o1;
			Pair<Long, Long> p2 = (Pair<Long, Long>) o2;

			if (p1.left > p2.left)

				return 1;

			else if (p1.left < p2.left)

				return -1;

			else

				return 0;
		}
	}

	public static List<ResultHandler> getClient_results() {
		return client_results;
	}

} public enum BuyingResult {
    BOUGHT, //Product bought
    NOT_AVAILABLE, //not available, the product has no stock, so you cant buy it
    OUT_OF_STOCK, //bought product, but there is no stock to deliver the product
    DOES_NOT_EXIST, //debug result, the item does not exist
    CANT_COMFIRM  //debug result, when we can't see the item stock after being bought

} public class Constants {

    public static /* final */ int NUM_EBS = 10;
    public static /* final */ int NUM_ITEMS = 10000;
    public static /* final */ int NUM_CUSTOMERS = NUM_EBS * 2880;
    public static /* final */ int NUM_ADDRESSES = 2 * NUM_CUSTOMERS;
    public static /* final */ int NUM_AUTHORS = (int) (.25 * NUM_ITEMS);
    public static /* final */ int NUM_ORDERS = (int) (.9 * NUM_CUSTOMERS);
    public static /* final */ int NUM_COUNTRIES = 92; // this is constant. Never changes!




} public class Address implements Entity {

    String street1;
    String street2;
    String city;
    String state;
    String zip;
    int country_id;
    int address_id;

    public Address(int key, String street1, String street2, String city, String state, String zip, int country) {

        Random r = new Random();
        this.street1 = street1;
        this.street2 = street2;
        this.city = city;
        this.state = state;
        this.zip = zip;
        this.country_id = country;
        this.address_id = key;
    }


    public int getAddress_id() {
        return address_id;
    }

    public void setAddress_id(int address_id) {
        this.address_id = address_id;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public int getCountry_id() {
        return country_id;
    }

    public void setCountry_id(int country_id) {
        this.country_id = country_id;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getStreet1() {
        return street1;
    }

    public void setStreet1(String street1) {
        this.street1 = street1;
    }

    public String getStreet2() {
        return street2;
    }

    public void setStreet2(String street2) {
        this.street2 = street2;
    }

    public String getZip() {
        return zip;
    }

    public void setZip(String zip) {
        this.zip = zip;
    }

    public TreeMap<String, Object> getValuesToInsert() {
        TreeMap<String, Object> values = new TreeMap<String, Object>();

        values.put("ADDR_STREET1", street1);
        values.put("ADDR_STREET2", street2);
        values.put("ADDR_CITY", city);
        values.put("ADDR_STATE", state);
        values.put("ADDR_ZIP", zip);
        values.put("ADDR_CO_ID", country_id);


        return values;
    }

    public String getKeyName() {
        return "ADDR_ID";
    }


} public class Customer implements Entity {

    int c_id;
    String C_UNAME, C_PASSWD, C_LNAME, C_FNAME;
    String C_PHONE;
    String C_EMAIL;
    Date since;
    Date lastLogin;
    Timestamp login;
    Timestamp expiration;
    double balance;
    double ytd_pmt;
    Date birthdate;
    String data;
    double C_DISCOUNT;
    int address;


    public Customer() {
    }

    public Customer(int C_ID, String C_UNAME, String C_PASSWD, String C_LNAME, String C_FNAME, String C_PHONE, String C_EMAIL, Date since, Date lastLogin, Timestamp login, Timestamp expiration, double balance, double ytd_pmt, Date birthdate, String data, double C_DISCOUNT, int address) {
        this.c_id = C_ID;
        this.C_UNAME = C_UNAME;
        this.C_PASSWD = C_PASSWD;
        this.C_LNAME = C_LNAME;
        this.C_FNAME = C_FNAME;
        this.C_PHONE = C_PHONE;
        this.C_EMAIL = C_EMAIL;
        this.since = since;
        this.lastLogin = lastLogin;
        this.login = login;
        this.expiration = expiration;
        this.balance = balance;
        this.ytd_pmt = ytd_pmt;
        this.birthdate = birthdate;
        this.data = data;
        this.C_DISCOUNT = C_DISCOUNT;
        this.address = address;
    }

    public double getC_DISCOUNT() {
        return C_DISCOUNT;
    }

    public void setC_DISCOUNT(double C_DISCOUNT) {
        this.C_DISCOUNT = C_DISCOUNT;
    }

    public String getC_EMAIL() {
        return C_EMAIL;
    }

    public void setC_EMAIL(String C_EMAIL) {
        this.C_EMAIL = C_EMAIL;
    }

    public String getC_FNAME() {
        return C_FNAME;
    }

    public void setC_FNAME(String C_FNAME) {
        this.C_FNAME = C_FNAME;
    }

    public String getC_LNAME() {
        return C_LNAME;
    }

    public void setC_LNAME(String C_LNAME) {
        this.C_LNAME = C_LNAME;
    }

    public String getC_PASSWD() {
        return C_PASSWD;
    }

    public void setC_PASSWD(String C_PASSWD) {
        this.C_PASSWD = C_PASSWD;
    }

    public String getC_PHONE() {
        return C_PHONE;
    }

    public void setC_PHONE(String c_PHONE) {
        C_PHONE = c_PHONE;
    }

    public int getAddress() {
        return address;
    }

    public void setAddress(int address) {
        this.address = address;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public Date getBirthdate() {
        return birthdate;
    }

    public void setBirthdate(Date birthdate) {
        this.birthdate = birthdate;
    }

    public int getC_id() {
        return c_id;
    }

    public void setC_id(int c_id) {
        this.c_id = c_id;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public Timestamp getExpiration() {
        return expiration;
    }

    public void setExpiration(Timestamp expiration) {
        this.expiration = expiration;
    }

    public Date getLastLogin() {
        return lastLogin;
    }

    public void setLastLogin(Date lastLogin) {
        this.lastLogin = lastLogin;
    }

    public Timestamp getLogin() {
        return login;
    }

    public void setLogin(Timestamp login) {
        this.login = login;
    }

    public Date getSince() {
        return since;
    }

    public void setSince(Date since) {
        this.since = since;
    }

    public double getYtd_pmt() {
        return ytd_pmt;
    }

    public void setYtd_pmt(double ytd_pmt) {
        this.ytd_pmt = ytd_pmt;
    }

    public String getC_UNAME() {
        return C_UNAME;
    }

    public void setC_UNAME(String C_UNAME) {
        this.C_UNAME = C_UNAME;
    }

    public TreeMap<String, Object> getValuesToInsert() {

        TreeMap<String, Object> values = new TreeMap<String, Object>();

        values.put("C_UNAME", C_UNAME);
        values.put("C_PASSWD", C_PASSWD);
        values.put("C_FNAME", C_FNAME);
        values.put("C_LNAME", C_LNAME);
        values.put("C_ADDR_ID", address);
        values.put("C_PHONE", C_PHONE);
        values.put("C_EMAIL", C_EMAIL);
        values.put("C_SINCE", since);
        values.put("C_LAST_VISIT", lastLogin);
        values.put("C_LOGIN", login);
        values.put("C_EXPIRATION", expiration);
        values.put("C_DISCOUNT", C_DISCOUNT);
        values.put("C_BALANCE", balance);
        values.put("C_YTD_PMT", ytd_pmt);
        values.put("C_BIRTHDATE", birthdate);
        values.put("C_DATA", data);

        return values;
    }

    public String getKeyName() {
        return "C_ID";
    }


} public class BenchmarkUtil {


    private static Random rand = new Random();

    private static final String[] digS = {
            "BA", "OG", "AL", "RI", "RE", "SE", "AT", "UL", "IN", "NG"
    };

    public static GregorianCalendar getRandomDate(int firstYar, int lastYear) {
        int month, day, year, maxday;

        year = getRandomInt(firstYar, lastYear);
        month = getRandomInt(0, 11);

        maxday = 31;
        if (month == 3 | month == 5 | month == 8 | month == 10) {
            maxday = 30;
        } else if (month == 1) {
            maxday = 28;
        }

        day = getRandomInt(1, maxday);
        return new GregorianCalendar(year, month, day);
    }

    public static int getRandomInt(int lower, int upper) {

        int num = (int) Math.floor(rand.nextDouble() * ((upper + 1) - lower));
        if (num + lower > upper || num + lower < lower) {
            System.out.println("ERROR: Random returned value of of range!");
            System.exit(1);
        }
        return num + lower;
    }

    public static int getRandomNString(int num_digits) {
        int return_num = 0;
        for (int i = 0; i < num_digits; i++) {
            return_num += getRandomInt(0, 9)
                    * (int) java.lang.Math.pow(10.0, (double) i);
        }
        return return_num;
    }

    public static String getRandomAString(int min, int max) {
        String newstring = new String();
        int i;
        final char[] chars = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', '#',
                '$', '%', '^', '&', '*', '(', ')', '_', '-', '=', '+',
                '{', '}', '[', ']', '|', ':', ';', ',', '.', '?', '/',
                '~'}; //78 characters
        int strlen = (int) Math.floor(rand.nextDouble() * ((max - min) + 1));
        if (strlen < 1) strlen = min;
        strlen += min;
        for (i = 0; i < strlen; i++) {
            char c = chars[(int) Math.floor(rand.nextDouble() * 78)];
            newstring = newstring.concat(String.valueOf(c));
        }
        return newstring;
    }


    public static byte[] getBytes(Object obj) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            oos.flush();
            oos.close();
            bos.close();
            byte[] data = bos.toByteArray();
            return data;
        } catch (IOException ex) {
            Logger.getLogger(BenchmarkUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static Object toObject(byte[] bytes) {
        try {
            Object object = null;
            object = new java.io.ObjectInputStream(new java.io.ByteArrayInputStream(bytes)).readObject();
            return object;
        } catch (IOException ex) {
            Logger.getLogger(BenchmarkUtil.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(BenchmarkUtil.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static String getRandomAString(int length) {
        String newstring = new String();
        int i;
        final char[] chars = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
                'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
                'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', '#',
                '$', '%', '^', '&', '*', '(', ')', '_', '-', '=', '+',
                '{', '}', '[', ']', '|', ':', ';', ',', '.', '?', '/',
                '~', ' '}; //79 characters
        for (i = 0; i < length; i++) {
            char c = chars[(int) Math.floor(rand.nextDouble() * 79)];
            newstring = newstring.concat(String.valueOf(c));
        }
        return newstring;
    }


    public static TreeMap<String, Integer> randomizeMap(Map<String, Integer> map) {

        Random r = new Random();
        TreeMap<String, Integer> new_map = new TreeMap<String, Integer>();
        for (String m : map.keySet()) {
            new_map.put(r.nextInt(10) + ":" + m, map.get(m));

        }
        return new_map;
    }

    public static String DigSyl(int d, int n) {
        String s = "";

        if (n == 0) return (DigSyl(d));
        for (; n > 0; n--) {
            int c = d % 10;
            s = digS[c] + s;
            d = d / 10;
        }

        return (s);
    }

    public static String DigSyl(int d) {
        String s = "";

        for (; d != 0; d = d / 10) {
            int c = d % 10;
            s = digS[c] + s;
        }

        return (s);
    }


    class MethodExecuter implements Runnable {

        Object invoked;
        Method m;
        Object[] parameters;

        MethodExecuter(Object invoked, Method m, Object[] parameters) {
            this.invoked = invoked;
            this.m = m;
            this.parameters = parameters;
        }

        public void run() {
            try {
                m.invoke(invoked, parameters);
            } catch (IllegalAccessException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            } catch (InvocationTargetException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

} public class SqlReader {


    public static Map<String, String> parse(String fileName) {


        Map<String, String> queryMap = new TreeMap<String, String>();
        try {
            // Open the file that is the first
            // command line parameter
            FileInputStream fstream = new FileInputStream(fileName);
            // Get the object of DataInputStream
            DataInputStream in = new DataInputStream(fstream);
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            String strLine;
            //Read File Line By Line
            String query_name = "";
            String query = "";
            while ((strLine = br.readLine()) != null) {

                if (strLine.trim().equals("") || strLine.trim().startsWith("#")) {
                    continue;
                } else if (strLine.startsWith("@")) {

                    if (!query_name.equals("") && !query.equals("")) {
                        queryMap.put(query_name, query);
                    }

                    query_name = strLine.split("=")[0];
                    query = strLine.replace(query_name + "=", "");
                } else {
                    query = query + strLine;
                }


            }
            //Close the input stream
            in.close();
        } catch (Exception e) {//Catch exception if any
            System.err.println("Error: " + e.getMessage());
        }

        return queryMap;

    }

    public static void main(String[] args) {
        Map<String, String> s = SqlReader.parse("conf/DataStore/sql-mysql.properties");
        for (String q : s.keySet()) {
            System.out.println(q + "=" + s.get(q));

        }
    }

} public class TPM_counter {

	int transactions =0;

	public void increment(){
		transactions++;
	}

	public int getTransactions(){
		return transactions;
	}

	public int get_and_reset(){
		int t = transactions;
		transactions =0;
		return t ;
	}
} public class ThinkTime {


    private static Random random = new Random();

    public static long getThinkTime() {

        if (BenchmarkMain.thinkTime == -1) {
            long simulatedDelay = (long) ((-Math.log(random.nextDouble()) * 7) * 1000d);

            if (simulatedDelay > 70000) {
                simulatedDelay = 70000;
            }

            return simulatedDelay;
        } else {
            return BenchmarkMain.thinkTime;
        }
    }
} public interface Entity {

    public String getKeyName();

    public TreeMap<String, Object> getValuesToInsert();

} public interface KeyGenerator {

    public Object getNextKey();

     public Object getNextKey(int client);
} public class Operation {

    //The operation name
    private String operation;

    //Parameters
    private Map<String, Object> parameters;

    //Operation result
    private Object result;

    public Operation(String operation, Map<String, Object> parameters) {
        this.operation = operation;
        this.parameters = parameters;
    }

    public String getOperation() {
        return operation;
    }

    public Map<String, Object> getParameters() {
        return parameters;
    }


    public Object getParameter(String name) throws NoSuchFieldException {
        if (parameters.containsKey(name)) {
            return parameters.get(name);
        } else {
            throw new NoSuchFieldException(name);
        }


    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }
} public interface WorkloadGeneratorInterface {


    /**
     * Get the next database operation
     *
     * @return the next Operation to be executed.
     */
    public Operation getNextOperation();

} public interface DatabaseExecutorInterface {




    /**
     * Start the benchmark process within the client.<br>
     * This operation should always be sequential, relying in the Executor class that handles the thread clients <br>
     *
     * @param workload         the workload generator that supplies the methods to be executed.
     * @param nodeId           the benchmark node where the client is executing.
     * @param operation_number the number of operation to execute.
     */
    public void start(WorkloadGeneratorInterface workload, BenchmarkNodeID nodeId, int operation_number, ResultHandler handler);


    /**
     * Start the benchmark process within the client.<br>
     * This operation should always be sequential, relying in the Executor class that handles the thread clients <br>
     *
     * @param op operation to be executed, and where the result is stored.
     */
    public void execute(Operation op) throws Exception;


    public Object insert(String key, String path, Entity value) throws Exception;


    public void remove(String key, String path, String column) throws Exception;


    public void update(String key, String path, String column, Object value, String superfield) throws Exception;


    public Object read(String key, String path, String column, String superfield) throws Exception;


    public Map<String, Map<String, Object>> rangeQuery(String table, List<String> fields, int limit) throws Exception;


    public void truncate(String path) throws Exception;

    public void index(String key,String path, Object value) throws Exception;

    public void index(String key,String path, String indexed_key ,Map<String,Object> value) throws Exception;
    

    public void closeClient();

    //info method
    public Map<String,String> getInfo();

}
import org.apache.log4j.Logger;
import org.uminho.gsd.benchmarks.benchmark.BenchmarkNodeID;
import org.uminho.gsd.benchmarks.dataStatistics.ResultHandler;
import org.uminho.gsd.benchmarks.generic.BuyingResult;
import org.uminho.gsd.benchmarks.generic.Constants;
import org.uminho.gsd.benchmarks.generic.entities.Address;
import org.uminho.gsd.benchmarks.generic.entities.Customer;
import org.uminho.gsd.benchmarks.helpers.BenchmarkUtil;
import org.uminho.gsd.benchmarks.helpers.SqlReader;
import org.uminho.gsd.benchmarks.helpers.TPM_counter;
import org.uminho.gsd.benchmarks.helpers.ThinkTime;
import org.uminho.gsd.benchmarks.interfaces.Entity;
import org.uminho.gsd.benchmarks.interfaces.KeyGenerator;
import org.uminho.gsd.benchmarks.interfaces.Workload.Operation;
import org.uminho.gsd.benchmarks.interfaces.Workload.WorkloadGeneratorInterface;
import org.uminho.gsd.benchmarks.interfaces.executor.DatabaseExecutorInterface;
import java.sql.*;
import java.sql.Date;
import java.util.*;
/*
 * *********************************************************************
 * Copyright (c) 2010 Pedro Gomes and Universidade do Minho.
 * All rights reserved.
 * 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.uminho.gsd.benchmarks.TPCW_MySQL.executor;




public class TPCW_MySQL_Executor implements DatabaseExecutorInterface {

	private Logger logger = Logger.getLogger(TPCW_MySQL_Executor.class);

	public static int TOP_SEARCH_LIMIT = 3000;
	public static int BEST_SELLERS_NUM = 10;


	/**
	 * Last used client - load balancing purposes *
	 */
	int last_writer = 0;
	int last_reader = 0;

	/**
	 * Database name*
	 */
	private String database_name;

	/**
	 * This client result logger*
	 */
	ResultHandler client_result_handler;

	/**
	 * Write connections*
	 */
	List<Connection> write_connections;

	/**
	 * Read connections*
	 */
	List<Connection> read_connections;

	/**
	 * The items bought within the client*
	 */
	Map<String, Integer> partialBought = new TreeMap<String, Integer>();
	/**
	 * The number of bought items*
	 */
	int bought_qty;
	/**
	 * The number of bought acts*
	 */
	int bought_actions;
	/**
	 * The number of bougth carts*
	 */
	int bought_carts;

	/**
	 * The number of 0s
	 */
	int zeros;

	/**
	 * GEnerator of ids
	 */
	KeyGenerator keyGenerator;