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 NodeKeyGenerator implements KeyGenerator {

    int nodeID;


    public NodeKeyGenerator(int nodeID) {
        this.nodeID = nodeID;
    }

    public synchronized Object getNextKey() {

        long timestamp = Long.MAX_VALUE - System.currentTimeMillis();
        //max long as 19 characters
        String key = timestamp + "";
        int length = key.length();

        String prefix = "";
        for (int i = length; i < 19; i++) {
            prefix = "0" + prefix;
        }

        key = key + "." + nodeID;

        return key;
    }

    public synchronized Object getNextKey(int client) {

        long timestamp = Long.MAX_VALUE - System.currentTimeMillis();
        //max long as 19 characters
        String key = timestamp + "";
        int length = key.length();

        String prefix = "";
        for (int i = length; i < 19; i++) {
            prefix = "0" + prefix;
        }

        key = key + "." + nodeID+ "."+client;

        return key;
    }
} 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 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 interface Entity {

    public String getKeyName();

    public TreeMap<String, Object> getValuesToInsert();

} public abstract class AbstractDatabaseExecutorFactory {

	/**
	 * Information collected from the configuration file *
	 */
	protected Map<String, Map<String, String>> conf;
	//Configuration file name
	private String dataStore_file_name;
	/**
	 * BenchmarkExecutor*
	 */
	protected BenchmarkExecutor executor;
	/**
	 * Benchmarking node id*
	 */
	protected BenchmarkNodeID nodeID;
	/**
	 * The number of clients in one node*
	 */
	protected int client_number;


	protected List<TPM_counter> tpm_counters = new LinkedList<TPM_counter>();


	private Timer data_extraction = new Timer("Statistics calculation", true);

	private ResultHandler stats_handler;

	private boolean do_tmp_counting = false;


	protected AbstractDatabaseExecutorFactory(BenchmarkExecutor executor, String conf_file) {

		this.dataStore_file_name = conf_file;
		this.executor = executor;
		loadFile();
	}

	/**
	 * Method that loads workload info.
	 */
	private void loadFile() {

		FileInputStream in = null;
		String jsonString_r = "";

		if (!dataStore_file_name.endsWith(".json")) {
			dataStore_file_name = dataStore_file_name + ".json";
		}

		try {
			in = new FileInputStream("conf/DataStore/" + dataStore_file_name);
			BufferedReader bin = new BufferedReader(new InputStreamReader(in));
			String s = "";
			StringBuilder sb = new StringBuilder();
			while (s != null) {
				sb.append(s);
				s = bin.readLine();
			}
			jsonString_r = sb.toString().replace("\n", "");
			bin.close();
			in.close();

		} catch (FileNotFoundException ex) {
			Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);
		} catch (IOException ex) {
			Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);

		} finally {
			try {
				in.close();
			} catch (IOException ex) {
				Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);
			}
		}

		Map<String, Map<String, String>> map = JsonUtil.getStringMapMapFromJsonString(jsonString_r);
		conf = map;
	}

	public abstract DatabaseExecutorInterface getDatabaseClient();


	public void startStats() {
		data_extraction.schedule(tpm_calculation, 60000, 60000);
	}

	public void setNodeId(BenchmarkNodeID id) {
		nodeID = id;
	}

	/**
	 * Sets the number of used clients in one node.
	 */
	public void setClientNumber(int client_number) {
		this.client_number = client_number;

	}


	public void setStats_handler(ResultHandler stats_handler) {
		this.stats_handler = stats_handler;
	}

	TimerTask tpm_calculation = new TimerTask() {

		public void run() {
			int tpm = 0;
			if (do_tmp_counting) {
				for (TPM_counter tpm_counter : tpm_counters) {
					tpm += tpm_counter.get_and_reset();
				}
			    if(stats_handler!=null){
					stats_handler.logResult("TPM", (tpm));
				//	System.out.println("TPM:" + tpm);
				}
			}

		}
	};


	public synchronized void registerCounter(TPM_counter tpm_counter) {
		tpm_counters.add(tpm_counter);
	}


	public void initTPMCounting() {
		do_tmp_counting = true;
	}

} 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();

} public abstract class AbstractBenchmarkPopulator {


    //The configuration file
    private String conf_filename;
    /**
     * Configuration map*
     */
    protected Map<String, Map<String, String>> configuration;
    /**
     * Database interface*
     */
    protected AbstractDatabaseExecutorFactory database_interface_factory;

    protected AbstractBenchmarkPopulator(AbstractDatabaseExecutorFactory database_interface_factory, String conf_filename) {
        this.conf_filename = conf_filename;
        this.database_interface_factory = database_interface_factory;
        loadFile();
    }

    /**
     * @return true if success, false otherwise
     */
    public abstract boolean populate();

    public abstract void cleanDB() throws Exception;

    public abstract void BenchmarkClean() throws Exception;

    public void loadFile() {


        FileInputStream in = null;
        String jsonString_r = "";

        if (!conf_filename.endsWith(".json")) {
            conf_filename = conf_filename + ".json";
        }

        try {
            in = new FileInputStream("conf/Populator/" + conf_filename);
            BufferedReader bin = new BufferedReader(new InputStreamReader(in));
            String s = "";
            StringBuilder sb = new StringBuilder();
            while (s != null) {
                sb.append(s);
                s = bin.readLine();
            }
            jsonString_r = sb.toString().replace("\n", "");
            bin.close();
            in.close();

        } catch (FileNotFoundException ex) {
            Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);

        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(AbstractDatabaseExecutorFactory.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        Map<String, Map<String, String>> map = JsonUtil.getStringMapMapFromJsonString(jsonString_r);
        configuration = map;
    }
} public class TPCW_Riak_Executor implements DatabaseExecutorInterface {

	private static final int BESTSELLERMAX = 50;
	private String keyspace;
	private Map<String, Integer> connections;
	private KeyGenerator keyGenerator;
	private ArrayList<IRiakClient> iclients;
	private ArrayList<RawClient> clients;
	//private ArrayList<RiakClient> swiftClients;
	private Map<String, String> paths;
	private TPM_counter counter;
	private long simulatedDelay;
	private int search_slice_ratio;
	private int global_executor_counter;
	private int executor_id;
	private ResultHandler client_result_handler;
	private Gson GSON = new Gson();

	//TODO: Não está implementado
	public static int INSERT_CONSISTENCY_LEVEL = 2;
	public static int REMOVE_CONSISTENCY_LEVEL = 2;
	public static int RANGE_CONSISTENCY_LEVEL = 2;
	public static int TRANSACTIONAL_CONSISTENCY_LEVEL = 2;
	public static int READ_CONSISTENCY_LEVEL = 2;
	public static int WRITE_CONSISTENCY_LEVEL = 2;
	public static int ALL = 10;

	private PBClusterConfig clusterConf;

	Map<String, Integer> partialBought = new TreeMap<String, Integer>();
	ArrayList<String> operations = new ArrayList<String>();
	int bought_qty;
	int bought_actions;
	int bought_carts;
	int zeros;
	private int debug_bougth_items;
	private int total_bought;
	int last, lastRaw = 0;

	private String[] credit_cards = { "VISA", "MASTERCARD", "DISCOVER", "AMEX",
			"DINERS" };
	private String[] ship_types = { "AIR", "UPS", "FEDEX", "SHIP", "COURIER",
			"MAIL" };
	private String[] status_types = { "PROCESSING", "SHIPPED", "PENDING",
			"DENIED" };

	private Random random = new Random();

	public TPCW_Riak_Executor(String keyspace,
			Map<String, Integer> connections,
		//	ConsistencyLevel[] consistencyLevels,
			Map<String, String> key_paths, int think_time, int search_slices,
			KeyGenerator keyGenerator, TPM_counter tpm_counter) {

		this.keyspace = keyspace;
		this.keyGenerator = keyGenerator;
		this.connections = connections;
//		INSERT_CONSISTENCY_LEVEL = consistencyLevels[0];
//		REMOVE_CONSISTENCY_LEVEL = consistencyLevels[1];
//		RANGE_CONSISTENCY_LEVEL = consistencyLevels[2];
//		TRANSACTIONAL_CONSISTENCY_LEVEL = consistencyLevels[3];
//		READ_CONSISTENCY_LEVEL = consistencyLevels[4];
//		WRITE_CONSISTENCY_LEVEL = consistencyLevels[5];
		this.iclients = new ArrayList<IRiakClient>();
		this.clients = new ArrayList<RawClient>();
		this.connections = connections;
		this.keyspace = keyspace;
		this.paths = key_paths;
		this.counter = tpm_counter;

		Map<String, Integer> sortedConnections = BenchmarkUtil
				.randomizeMap(connections);

		for (int i = 0; i < 10; i++) {
			for (String rand_host : sortedConnections.keySet()) {
				String host = rand_host.split(":")[1];
				try {
					IRiakClient client = RiakFactory.pbcClient();
					iclients.add(client);
				} catch (RiakException e) {
					e.printStackTrace();
				}

			}
		}

		for (int i = 0; i < 10; i++) {
			for (String rand_host : sortedConnections.keySet()) {
				com.basho.riak.pbc.RiakClient pbcClient;
				try {
					pbcClient = new com.basho.riak.pbc.RiakClient(rand_host.split(":")[1]);
					RawClient rawClient = null;
					rawClient = new PBClientAdapter(pbcClient);
					clients.add(rawClient);
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

			}
		}

		search_slice_ratio = search_slices;
		simulatedDelay = think_time;

	}

	@Override
	public void start(WorkloadGeneratorInterface workload,
			BenchmarkNodeID nodeId, int operation_number, ResultHandler handler) {

		global_executor_counter++;
		executor_id = global_executor_counter;
		client_result_handler = handler;

		for (int operation = 0; operation < operation_number; operation++) {
			long g_init_time = System.currentTimeMillis();

			try {
				long init_time = System.currentTimeMillis();

				Operation op = workload.getNextOperation();
				executeMethod(op);
				long end_time = System.currentTimeMillis();
				client_result_handler.logResult(op.getOperation(),
						(end_time - init_time));

				simulatedDelay = ThinkTime.getThinkTime();

				if (simulatedDelay > 0) {
					Thread.sleep(simulatedDelay);
				}

			} catch (NoSuchFieldException e) {
				System.out.println("[ERROR:] THIS OPERATION DOES NOT EXIST: "
						+ e.getMessage());
				break;
			} catch (InterruptedException e) {
				System.out
						.println("[ERROR:] THINK TIME AFTER METHOD EXECUTION INTERRUPTED: "
								+ e.getMessage());
				break;

			} catch (Exception e) {
				e.printStackTrace();
				System.out.println("-- Error : Client " + executor_id
						+ " going down....");
				break;

			}
			long end_time = System.currentTimeMillis();
			counter.increment();
			client_result_handler.logResult("OPERATIONS",
					(end_time - g_init_time));

		}

		client_result_handler.getResulSet().put("bought", partialBought);
		client_result_handler.getResulSet().put("total_bought", bought_qty);
		client_result_handler.getResulSet().put("buying_actions",
				bought_actions);
		client_result_handler.getResulSet().put("bought_carts", bought_carts);
		client_result_handler.getResulSet().put("zeros", zeros);

	}

	public void execute(Operation op) throws Exception {
		executeMethod(op);
	}

	public void executeMethod(Operation op) throws Exception {

		if (op == null) {
			System.out.println("[ERROR]: NULL OPERATION");
			return;
		}

		operations.add(op.getOperation());

		String method_name = op.getOperation();

		if (method_name.equalsIgnoreCase("GET_STOCK_AND_PRODUCTS")) {
			ArrayList<String> fields = new ArrayList<String>();
			fields.add("I_TITLE");
			fields.add("I_STOCK");
			Map<String, Map<String, Object>> items_info = rangeQuery("Item",
					fields, -1);

			op.setResult(items_info);

		} else if (method_name
				.equalsIgnoreCase("Get_Stock_And_Products_after_increment")) {

			ArrayList<String> fields = new ArrayList<String>();
			int stock = (Integer) op.getParameter("STOCK");
			setItemStocks(stock);

			System.out.println("sleeeping after stock reposition...");
			Thread.sleep(60000);

			fields.add("I_STOCK");
			Map<String, Map<String, Object>> items_info = rangeQuery("item",
					fields, -1);
			op.setResult(items_info);

		} else if (method_name.equalsIgnoreCase("GET_ITEM_STOCK")) {

			String item_id = (String) op.getParameters().get("ITEM_ID");

			Object o = read(item_id, "item", "I_STOCK", null);
			int stock = -1;
			if (o != null) {
				stock = (Integer) o;
			}
			op.setResult(stock);

		} else if (method_name.equalsIgnoreCase("ADD_TO_CART")) {

			String cart = (String) op.getParameter("CART_ID");
			String item_id = (String) op.getParameter("ITEM_ID");
			int qty = (Integer) op.getParameter("QTY");

			addToCart(cart, item_id, qty);

		} else if (method_name.equalsIgnoreCase("BUY_CART")) {

			bought_carts++;
			String cart_id = (String) op.getParameter("CART_ID");

			Customer c = null;

			if (op.getParameters().containsKey("Customer")) {
				c = (Customer) op.getParameter("Customer");
			}
			buyCart(cart_id, c);

		} else if (method_name.equalsIgnoreCase("GET_BENCHMARK_RESULTS")) {
			// op.setResult(getResults());

		} else if (method_name.equalsIgnoreCase("OP_HOME")) {

			int costumer = (Integer) op.getParameter("COSTUMER");
			int item_id = (Integer) op.getParameter("ITEM");
			HomeOperation(costumer, item_id);
		} else if (method_name.equalsIgnoreCase("OP_SHOPPING_CART")) {

			String cart = (String) op.getParameter("CART");
			int item_id = (Integer) op.getParameter("ITEM");
			boolean create = (Boolean) op.getParameter("CREATE");
			shoppingCartInteraction(item_id, create, cart);

		} else if (method_name.equalsIgnoreCase("OP_REGISTER")) {
			String customer = (String) op.getParameter("CUSTOMER");

			CustomerRegistration(customer);

		} else if (method_name.equalsIgnoreCase("OP_LOGIN")) {

			String customer = (String) op.getParameter("CUSTOMER");

			// TODO: Para descomentar refreshSession(customer);

		} else if (method_name.equalsIgnoreCase("OP_BUY_REQUEST")) {

			String id = (String) op.getParameter("CART");
			BuyRequest(id);

		} else if (method_name.equalsIgnoreCase("OP_BUY_CONFIRM")) {

			String car_id = (String) op.getParameter("CART");
			String costumer = (String) op.getParameter("CUSTOMER");
			BuyComfirm(costumer, car_id);

		} else if (method_name.equalsIgnoreCase("OP_ORDER_INQUIRY")) {
			String costumer = (String) op.getParameter("CUSTOMER");

			OrderInquiry(costumer);

		} else if (method_name.equalsIgnoreCase("OP_SEARCH")) {
			String term = (String) op.getParameter("TERM");
			String field = (String) op.getParameter("FIELD");

			// TODO: Para descomentar doSearch(term, field);

		} else if (method_name.equalsIgnoreCase("OP_NEW_PRODUCTS")) {
			String field = (String) op.getParameter("FIELD");
			newProducts(field);

		} else if (method_name.equalsIgnoreCase("OP_BEST_SELLERS")) {
			String field = (String) op.getParameter("FIELD");
			BestSellers(field);
		} else if (method_name.equalsIgnoreCase("OP_ITEM_INFO")) {
			int id = (Integer) op.getParameter("ITEM");
			ItemInfo(id);
		} else if (method_name.equalsIgnoreCase("OP_ADMIN_CHANGE")) {
			int id = (Integer) op.getParameter("ITEM");
			AdminChange(id);

		} else if (method_name.equalsIgnoreCase("")) {

		} else {
			System.out.println("[WARN:]UNKNOWN REQUESTED METHOD: "
					+ method_name);

		}
	}

	@Override
	public Object insert(String key, String path, Entity value)
			throws Exception {

		TreeMap<String, Object> values_to_insert = value.getValuesToInsert();
		path = path.toLowerCase();
		modifyOrInsertListOfColumns(key, path, values_to_insert,
				INSERT_CONSISTENCY_LEVEL);

		return null;
	}

	@Override
	public void remove(String key, String path, String column) throws Exception {
		List<String> columns = null;
		if (column != null) {
			columns = new ArrayList<String>();
			columns.add(column);
		}
		removeKeyOrColumn(key, path, columns, REMOVE_CONSISTENCY_LEVEL);
	}

	public void update(String key, String bucketName, String column,
			Object value, String superfield) throws Exception {

		if (superfield != null) {
			System.out.println("Não é suposto acontecer");
		}
		Bucket bucket = getBucket(bucketName);
		String objectString = bucket.fetch(key).execute().getValueAsString();
		Entity entity = (Entity) GSON.fromJson(objectString,
				getEntityClass(bucketName));
		insertOrModifyAttribute(entity, value, column, WRITE_CONSISTENCY_LEVEL);
		getBucket(bucketName).store(key, GSON.toJson(entity).toString())
				.execute();
	}

	public Object read(String key, String bucketName, String column,
			String superfield) throws Exception {
		Bucket bucket = getBucket(bucketName);
		Entity entity = (Entity) GSON.fromJson(bucket.fetch(key).execute()
				.getValueAsString(), getEntityClass(bucketName));
		Field fld = getEntityClass(bucketName).getField(column);
		Object ret = fld.get(entity);
		return ret;

	}

	@Override
	public Map<String, Map<String, Object>> rangeQuery(String bucketName,
			List<String> fields, int limit) throws Exception {
		int i = 0;
		Iterable<String> it = getRawClient().listKeys(bucketName);
		Bucket bucket = getBucket(bucketName);
		Map<String, Map<String, Object>> results = new HashMap<String, Map<String, Object>>();
		for (String key : it) {
			IRiakObject objRiak = bucket.fetch(key).execute();
			Entity obj = (Entity) GSON.fromJson(objRiak.getValueAsString(),
					getEntityClass(bucketName));

			Map<String, Object> columnValues = new HashMap<String, Object>();
			for (Entry<String, Object> pair : obj.getValuesToInsert()
					.entrySet()) {
				columnValues.put(pair.getKey(), pair.getValue());
			}
			results.put(key, columnValues);
			i++;
			if (!(i < limit || limit == -1)) {
				break;
			}
		}
		return results;
	}

	@Override
	public void truncate(String bucketName) throws Exception {
		Bucket bucket = getBucket(bucketName);
		Iterable<String> it = bucket.keys();
		for (String key : it) {
			removeKeyOrColumn(key, bucketName, null, WRITE_CONSISTENCY_LEVEL);
		}

	}

	@Override
	public void index(String key, String path, Object value) throws Exception {

	}

	@Override
	public void index(String key, String path, String indexed_key,
			Map<String, Object> value) throws Exception {
		// TODO Auto-generated method stub

	}

	public void index(String key, String path, String indexed_key,
			AuthorIndex entity) throws Exception {

	}

	@Override
	public void closeClient() {
	}

	@Override
	public Map<String, String> getInfo() {
		TreeMap<String, String> info = new TreeMap<String, String>();
		return info;
	}

	/********************************************************/
	/**** TPCW benchmark consistency and old operations ****/
	/**
	 * ****************************************************
	 */

	public void setItemStocks(int initial_stock) throws Exception {

		ArrayList<String> fields = new ArrayList<String>();
		fields.add("I_STOCK");
		Map<String, Map<String, Object>> items_info = rangeQuery("item",
				fields, -1);

		for (String key : items_info.keySet()) {
			insert(initial_stock, key, "item", "I_STOCK", ALL);
		}

	}

	/*
	 * Adiciona uma certa quantidade de itens a um carrinho
	 */
	public void addToCart(String cart, String item, int qty_to_add)
			throws Exception {
		int itemInt = Integer.parseInt(item);

		Bucket bucket = getBucket("shopping_cart");
		IRiakObject obj = bucket.fetch(cart).execute();
		ShoppingCart sc = GSON.fromJson(obj.getValueAsString(),
				ShoppingCart.class);

		SCLine sc_line = sc.getSCLine(itemInt);
		sc_line.setSCL_QTY(sc_line.getSCL_QTY() + qty_to_add);
		getBucket("shopping_cart").store(cart, GSON.toJson(sc).toString())
				.execute();
	}

	/*
	 * Actualiza Stock e quantidade de itens vendidos
	 */
	public BuyingResult BuyCartItem(String item, int qty) throws Exception {
		total_bought++;

		try {
			Item itemObj = (Item) GSON.fromJson(getBucket("item").fetch(item)
					.execute().getValueAsString(), Item.class);

			if (itemObj == null) {
				return BuyingResult.DOES_NOT_EXIST;
			}
			int stock = itemObj.getI_STOCK();
			if ((stock - qty) >= 0) { // if stock is sufficient

				if (stock - qty == 0) {
					zeros++;
				}

				stock -= qty;
				itemObj.setI_STOCK(stock);
				itemObj.setI_TOTAL_SOLD(itemObj.getI_TOTAL_SOLD() + qty);

				BestSellerEntry bse = new BestSellerEntry(
						itemObj.getI_SUBJECT(), Integer.parseInt(item),
						itemObj.getI_TOTAL_SOLD());

				getBucket("BestSellersBuff").store(item + "",
						GSON.toJson(bse).toString()).execute();

				getBucket("item").store(item, GSON.toJson(itemObj).toString());

			} else {
				return BuyingResult.NOT_AVAILABLE;
			}
			debug_bougth_items++;
			return BuyingResult.BOUGHT;

		} catch (Exception e) {
			return BuyingResult.CANT_COMFIRM;
		}

	}

	public BuyingResult buyItem(String item_id, int qty) throws Exception {
		long init_time = System.currentTimeMillis();
		BuyingResult result = BuyCartItem(item_id, qty);
		long end_time = System.currentTimeMillis();
		client_result_handler.logResult("BUY_ITEM", (end_time - init_time));
		List<Object> buying_information = new LinkedList<Object>();
		buying_information.add(qty);
		buying_information.add(init_time);
		buying_information.add(end_time);
		client_result_handler.record_unstructured_data("BOUGHT_ITEMS_TIMELINE",
				item_id + "", buying_information);

		return result;
	}

	// Compra os itens do carrinho
	// actualiza o stock, e os tops
	public void buyCart(String cart_id, Customer c) throws Exception {

		Bucket bucket = getBucket("shopping_cart");
		ShoppingCart shop_c = (ShoppingCart) GSON.fromJson(
				bucket.fetch(cart_id + "").execute().getValueAsString(),
				ShoppingCart.class);
		/*
		 * Map<String, Set<String>> map = new HashMap<String, Set<String>>();
		 * Set<String> list = new HashSet<String>(); list.add(shop_c.SC_C_ID);
		 * map.put("shopping_cart", list); MapReduceResponse res =
		 * getRiakClient().mapReduceOverObjects(map) .link("sc_lines",
		 * "cartline", false)
		 * .map(JavascriptFunction.named("Riak.mapValuesJson"), true) .submit();
		 */
		for (SCLine line : shop_c.SCLine) {
			BuyingResult result = buyItem(line.I_ID + "", line.SCL_QTY);
			client_result_handler.countEvent("BUYING_COUNTERS", result.name(),
					1);

			if (result.equals(BuyingResult.BOUGHT)) {
				bought_qty += line.SCL_QTY;
				bought_actions++;
				if (!partialBought.containsKey(line.I_ID)) {
					partialBought.put(line.I_ID + "", line.SCL_QTY);

				} else {
					int bought = partialBought.get(line.I_ID + "");
					partialBought.put(line.I_ID + "", (line.SCL_QTY + bought));
				}

			}
		}
	}

	/*
	 * 
	 * public Map<String, Map<String, Map<String, Object>>> getResults() throws
	 * Exception {
	 * 
	 * String column_family = "results"; Map<String, Map<String, Map<String,
	 * Object>>> results = new TreeMap<String, Map<String, Map<String,
	 * Object>>>(); SlicePredicate predicate = new SlicePredicate(); SliceRange
	 * slice_range = new SliceRange("".getBytes(), "".getBytes(), false, 10500);
	 * 
	 * ColumnParent parent = new ColumnParent();
	 * parent.setColumn_family(column_family);
	 * predicate.setSlice_range(slice_range);
	 * 
	 * String last_key = "";
	 * 
	 * 
	 * KeyRange range = new KeyRange(); range.setStart_key("");
	 * range.setEnd_key(""); range.setCount(search_slice_ratio);
	 * 
	 * boolean terminated = false;
	 * 
	 * while (!terminated) { List<KeySlice> keys =
	 * getCassandraClient().get_range_slices(keyspace, parent, predicate, range,
	 * ConsistencyLevel.ONE); //delay();
	 * 
	 * if (keys.isEmpty()) {
	 * System.out.println("[INFO|CASSANDRA:]The key range is empty"); } else {
	 * last_key = keys.get(keys.size() - 1).key; range.setStart_key(last_key); }
	 * ColumnPath path = new ColumnPath(); path.setColumn_family(column_family);
	 * for (KeySlice key : keys) { if (!key.columns.isEmpty()) { String key_name
	 * = key.key; //for each client if (!results.containsKey(key_name)) {
	 * results.put(key_name, new TreeMap<String, Map<String, Object>>()); } for
	 * (ColumnOrSuperColumn c : key.getColumns()) { if (c.isSetSuper_column()) {
	 * String superColumn_name = null; //for each item try { superColumn_name =
	 * new String(c.getSuper_column().getName(), "UTF-8"); } catch
	 * (UnsupportedEncodingException e) { e.printStackTrace(); //To change body
	 * of catch statement use File | Settings | File Templates. } if
	 * (!results.get(key_name).containsKey(superColumn_name)) {
	 * results.get(key_name).put(superColumn_name, new TreeMap<String,
	 * Object>()); } for (Column co : c.getSuper_column().columns) {
	 * results.get(key_name).get(superColumn_name).put(new String(co.getName()),
	 * BenchmarkUtil.toObject(co.getValue())); } } } }
	 * 
	 * } if (keys.size() < search_slice_ratio) { terminated = true; } } return
	 * results;
	 * 
	 * 
	 * }
	 */
	/**************************************/
	/**** TPCW benchmark operations ****/
	/**
	 * ********************************
	 */

	// Receives an Costumer id and retrieves is name
	// Receives a item and returns the id and thumbnail of related.
	public void HomeOperation(int customer, int item) throws Exception {

		Bucket bucket = getBucket("item");
		Item itemObj = (Item) GSON.fromJson(bucket.fetch(item + "").execute()
				.getValueAsString(), Item.class);
		bucket = getBucket("customer");
		Customer customerObj = (Customer) GSON.fromJson(
				bucket.fetch(customer + "").execute().getValueAsString(),
				Customer.class);
	}

	/*
	 * 
	 * Adiciona um item com quantidade 1 ao carrinho cria um carrinho novo se
	 * 'create'
	 */

	public void shoppingCartInteraction(int item, boolean create, String cart_id)
			throws Exception {
		ShoppingCart shop_c;
		IRiakObject shop_cObj;
		if (create) {
			Timestamp stamp = new Timestamp(System.currentTimeMillis());
			shop_c = new ShoppingCart(cart_id);
			shop_c.setCartInfo("SC_DATE", stamp.toString());
			shop_cObj = RiakObjectBuilder.newBuilder("shopping_cart", cart_id)
					.build();

		} else {
			Bucket bucket = getBucket("shopping_cart");
			shop_cObj = bucket.fetch(cart_id).execute();
			shop_c = (ShoppingCart) GSON.fromJson(shop_cObj.getValueAsString(),
					ShoppingCart.class);
		}
		Bucket bucket = getBucket("item");
		Item itemObj = (Item) GSON.fromJson(bucket.fetch(item + "").execute()
				.getValueAsString(), Item.class);

		SCLine sc_line = shop_c.getSCLine(item);

		if (sc_line != null) {
			sc_line.setSCL_QTY(sc_line.getSCL_QTY() + 1);
		} else {
			sc_line = new SCLine(item);
			sc_line.setSCL_COST(itemObj.getI_COST());
			sc_line.setSCL_SRP(itemObj.getI_SRP());
			sc_line.setSCL_TITLE(itemObj.getI_TITLE());
			sc_line.setSCL_BACKING(itemObj.getI_BACKING());
			sc_line.setSCL_QTY(1);
			sc_line.setI_ID(itemObj.getI_id());
			shop_c.addSCLine(sc_line);
			// getBucket("sc_lines").store(cart_id + "_" + item,
			// GSON.toJson(sc_line)).execute();
		}

		shop_cObj.setValue(GSON.toJson(shop_c));
		getBucket("shopping_Cart").store(cart_id + "",
				GSON.toJson(shop_c).toString()).execute();

	}

	/*
	 * Registo de utilizador
	 */

	public void CustomerRegistration(String costumer_id) throws Exception {

		String name = (BenchmarkUtil.getRandomAString(8, 13) + " " + BenchmarkUtil
				.getRandomAString(8, 15));
		String[] names = name.split(" ");
		Random r = new Random();
		int random_int = r.nextInt(1000);

		String key = names[0] + "_" + (costumer_id);

		String pass = names[0].charAt(0) + names[1].charAt(0) + "" + random_int;

		String first_name = names[0];

		String last_name = names[1];

		int phone = r.nextInt(999999999 - 100000000) + 100000000;

		String email = key + "@" + BenchmarkUtil.getRandomAString(2, 9)
				+ ".com";

		double discount = r.nextDouble();

		String adress = "Street: "
				+ (BenchmarkUtil.getRandomAString(8, 15) + " " + BenchmarkUtil
						.getRandomAString(8, 15)) + " number: "
				+ r.nextInt(500);

		double C_BALANCE = 0.00;

		double C_YTD_PMT = (double) BenchmarkUtil.getRandomInt(0, 99999) / 100.0;

		GregorianCalendar cal = new GregorianCalendar();
		cal.add(Calendar.DAY_OF_YEAR, -1 * BenchmarkUtil.getRandomInt(1, 730));

		java.sql.Date C_SINCE = new java.sql.Date(cal.getTime().getTime());

		cal.add(Calendar.DAY_OF_YEAR, BenchmarkUtil.getRandomInt(0, 60));
		if (cal.after(new GregorianCalendar())) {
			cal = new GregorianCalendar();
		}

		java.sql.Date C_LAST_LOGIN = new java.sql.Date(cal.getTime().getTime());

		java.sql.Timestamp C_LOGIN = new java.sql.Timestamp(
				System.currentTimeMillis());

		cal = new GregorianCalendar();
		cal.add(Calendar.HOUR, 2);

		java.sql.Timestamp C_EXPIRATION = new java.sql.Timestamp(cal.getTime()
				.getTime());

		cal = BenchmarkUtil.getRandomDate(1880, 2000);
		java.sql.Date C_BIRTHDATE = new java.sql.Date(cal.getTime().getTime());

		String C_DATA = BenchmarkUtil.getRandomAString(100, 500);

		String address_id = insertAdress();

		Customer c = new Customer(costumer_id, key, pass, last_name,
				first_name, phone + "", email, C_SINCE.toString(),
				C_LAST_LOGIN.toString(), C_LOGIN.toString(),
				C_EXPIRATION.toString(), C_BALANCE, C_YTD_PMT,
				C_BIRTHDATE.toString(), C_DATA, discount, address_id);

		insert(costumer_id, "customer", c);

	}

	public String insertAdress() throws Exception {

		String ADDR_STREET1, ADDR_STREET2, ADDR_CITY, ADDR_STATE;
		String ADDR_ZIP;
		int country_id;

		ADDR_STREET1 = "street" + BenchmarkUtil.getRandomAString(10, 30);

		ADDR_STREET2 = "street" + BenchmarkUtil.getRandomAString(10, 30);
		ADDR_CITY = BenchmarkUtil.getRandomAString(4, 30);
		ADDR_STATE = BenchmarkUtil.getRandomAString(2, 20);
		ADDR_ZIP = BenchmarkUtil.getRandomAString(5, 10);
		country_id = BenchmarkUtil.getRandomInt(0, 92 - 1);

		String key = ADDR_STREET1 + ADDR_STREET2 + ADDR_CITY + ADDR_STATE
				+ ADDR_ZIP + country_id;

		pt.fct.di.benchmarks.TPCW_Riak.entities.Address address = new Address(
				key, ADDR_STREET1, ADDR_STREET2, ADDR_CITY, ADDR_STATE,
				ADDR_ZIP, country_id);

		if (getBucket("address").fetch(key).execute() == null) { // does
			insert(key, "address", address);
		}

		return key;
	}

	public void refreshSession(String C_ID) throws Exception {

		Customer customer = GSON.fromJson(getBucket("customer").fetch(C_ID)
				.execute().getValueAsString(), Customer.class);
		Address address = GSON.fromJson(
				getBucket("address").fetch(customer.getAddress()).execute()
						.getValueAsString(), Address.class);
		customer.setLogin(new Timestamp(System.currentTimeMillis()).toString());
		customer.setExpiration((new Timestamp(
				System.currentTimeMillis() + 7200000)).toString());
		getBucket("customer").store(GSON.toJson(customer).toString()).execute();
	}

	/*
	 * Obtem carrinho Para todas as linhas soma a quantidade e o custo Actualiza
	 * os valores numericos do carrinho
	 */
	public void BuyRequest(String shopping_id) throws
			RiakRetryFailedException, JsonSyntaxException,
			UnresolvedConflictException, ConversionException, JSONException {

		Bucket bucket = getBucket("shopping_cart");
		ShoppingCart shop_c = (ShoppingCart) GSON.fromJson(
				bucket.fetch(shopping_id + "").execute().getValueAsString(),
				ShoppingCart.class);

		int qty = 0;
		float cost = 0;

		Collection<SCLine> scLines = shop_c.getSCLines();
		for (SCLine line : scLines) {

			int qty_read = line.getSCL_QTY();
			qty += qty_read;
			cost += line.getSCL_COST();

		}

		Float SC_SUB_TOTAL = cost * (1 - 0.2f);
		Float SC_TAX = SC_SUB_TOTAL * 0.0825f;
		Float SC_SHIP_COST = 3.00f + (1.00f * qty);
		Float SC_TOTAL = SC_SUB_TOTAL + SC_SHIP_COST + SC_TAX;
		shop_c.setCartInfo("SC_SUB_TOTAL", SC_SUB_TOTAL);// cheats...
		shop_c.setCartInfo("SC_TAX", SC_TAX);
		shop_c.setCartInfo("SC_SHIP_COST", SC_SHIP_COST);
		shop_c.setCartInfo("SC_TOTAL", SC_TOTAL);

		bucket = getBucket("shopping_cart");
		bucket.store(shopping_id + "", GSON.toJson(shop_c).toString())
				.execute();
	}

	/*
	 * Recebe um customer e um carrinho cria um order e um ccxact ccxact
	 * indexado por order_id
	 */
	public void BuyComfirm(String customer, String cart) throws Exception {

		Bucket bucket = getBucket("shopping_cart");
		ShoppingCart shop_c = (ShoppingCart) GSON.fromJson(bucket.fetch(cart)
				.execute().getValueAsString(), ShoppingCart.class);

		bucket = getBucket("customer");
		Customer customerObj = (Customer) GSON.fromJson(bucket.fetch(customer)
				.execute().getValueAsString(), Customer.class);

		double c_discount = (Double) customerObj.getC_DISCOUNT();

		String ship_addr_id = "";
		String cust_addr = (String) customerObj.getAddress();

		float decision = random.nextFloat();
		if (decision < 0.2) {
			ship_addr_id = insertAdress();
		} else {
			ship_addr_id = cust_addr;
		}

		String[] ids = cart.split("\\.");
		int thread_id = Integer.parseInt(ids[1]);

		String shipping = ship_types[random.nextInt(ship_types.length)];

		float total = 0;
		try {
			total = (Float) shop_c.cartInfo.getSC_TOTAL();
		} catch (Exception e) {
			System.out.println("Null pointer on cart:" + cart);
			System.out.println("OPERATIONS: " + operations.toString());
			e.printStackTrace();
			return;
		}

		String order_id = enterOrder(customer, thread_id, shop_c, ship_addr_id,
				cust_addr, shipping, total, c_discount);

		String cc_type = BenchmarkUtil.getRandomAString(10);
		long cc_number = BenchmarkUtil.getRandomNString(16);
		String cc_name = BenchmarkUtil.getRandomAString(30);
		Date cc_expiry = new Date(System.currentTimeMillis()
				+ random.nextInt(644444400));

		enterCCXact(order_id, customer, cc_type, cc_number, cc_name,
				cc_expiry.toString(), total, ship_addr_id.toString());

	}

	/*
	 * Recebe um customer e um shopping cart Cria um order adiciona orderLines
	 * actualiza a quantidade de items vendidos, actualiza a quantidade de
	 * vendidos. Indica que o customer fez um order novo Operaçao pesada
	 */
	public String enterOrder(String customer_id, int thread_id,
			ShoppingCart shoppingCart, String ship_addr_id, String cust_addr,
			String shipping, float total, double c_discount) throws Exception {
		String key = (String) keyGenerator.getNextKey(thread_id);

		float subTotal = (Float) shoppingCart.getCartInfo("SC_SUB_TOTAL");
		float tax = (Float) shoppingCart.getCartInfo("SC_TAX");
		float ship = (Float) shoppingCart.getCartInfo("SC_SHIP_COST");
		String shipType = ship_types[random.nextInt(ship_types.length)];
		String status = status_types[random.nextInt(status_types.length)];

		Order order = new Order(key, customer_id, new Date(
				System.currentTimeMillis()).toString(), subTotal, tax, total,
				shipType, new Date(System.currentTimeMillis()
						+ random.nextInt(604800000)).toString(), status,
				cust_addr, ship_addr_id);

		int index = 0;

		/*
		 * Map<String, Set<String>> map = new HashMap<String, Set<String>>();
		 * Set<String> list = new HashSet<String>();
		 * list.add(shoppingCart.SC_C_ID); map.put("shopping_cart", list);
		 * MapReduceResponse res = getRiakClient().mapReduceOverObjects(map)
		 * .link("sc_lines", "cartline", false)
		 * .map(JavascriptFunction.named("Riak.mapValuesJson"), true) .submit();
		 */

		for (SCLine item : shoppingCart.getSCLines()) {
			int qty = item.getSCL_QTY();
			int item_id = item.getI_ID();

			String ol_key = key + "." + index;

			OrderLine orderLine = new OrderLine(ol_key, key, item_id, qty,
					c_discount, BenchmarkUtil.getRandomAString(20, 100));

			index++;

			order.addOrderLine(orderLine);

			int item_i = orderLine.OL_QTY;
			Item itemFromBucket = GSON.fromJson(
					getBucket("item").fetch(item_id + "").execute()
							.getValueAsString(), Item.class);
			int stock = (Integer) itemFromBucket.getI_STOCK();
			int new_stock = stock - item_i;

			itemFromBucket.setI_STOCK(new_stock);
			itemFromBucket.setI_TOTAL_SOLD(itemFromBucket.getI_TOTAL_SOLD()
					+ item_i);

			BestSellerEntry bse = new BestSellerEntry(itemFromBucket.I_SUBJECT,
					item_id, itemFromBucket.getI_TOTAL_SOLD());

			getBucket("BestSellersBuff").store(item_id + "",
					GSON.toJson(bse).toString()).execute();
			getBucket("item").store(item_id + "",
					GSON.toJson(itemFromBucket).toString());
		}
		Customer customer = (Customer) GSON.fromJson(getBucket("customer")
				.fetch(customer_id).execute().getValueAsString(),
				Customer.class);
		customer.setC_O_LAST_ID(key);

		getBucket("customer").store(customer_id,
				GSON.toJson(customer).toString());
		getBucket("order").store(key, GSON.toJson(order).toString()).execute();
		return customer_id;
	}

	public void enterCCXact(String order_id, String customer, String cc_type,
			long cc_number, String cc_name, String cc_expiry, float total,
			String ship_addr_id) throws Exception {

		Bucket bucket = getBucket("cc_xacts");
		int co_id = (Integer) readfromColumn(ship_addr_id, "address",
				"ADDR_CO_ID", READ_CONSISTENCY_LEVEL);
		CCXactItem ccxactItem = new CCXactItem(cc_type, cc_number, cc_name,
				cc_expiry, total, cc_expiry, order_id, co_id);
		bucket = getBucket("cc_xacts");
		bucket.store(order_id, GSON.toJson(ccxactItem).toString()).execute();

	}

	// TODO: OS fetchs devem estar melhorados com os links
	public void OrderInquiry(String customer) throws Exception {

		Bucket bucket = getBucket("customer");
		IRiakObject obj = bucket.fetch(customer).execute();
		Customer customerObj = (Customer) GSON.fromJson(obj.getValueAsString(),
				Customer.class);
		
		if (customerObj.getC_O_LAST_ID() == null) {
			// System.out.println("Cliente nunca fez orders");
			return;
		} else {
			// System.out.println("Cliente ja fez orders");
		}

		IRiakObject orderRiak = getBucket("order").fetch(
				customerObj.getC_O_LAST_ID()).execute();

		Order orderObj = (Order) GSON.fromJson(orderRiak.getValueAsString(),
				Order.class);

		IRiakObject CC_XACTS_obj = getBucket("cc_xacts").fetch(customer)
				.execute();

		IRiakObject o_bill_addr_id_obj = getBucket("address").fetch(
				orderObj.getO_BILL_ADDR_ID()).execute();
		Address o_bill_addr_id = (Address) GSON.fromJson(
				o_bill_addr_id_obj.getValueAsString(), Address.class);
		IRiakObject o_ship_addr_id_obj = getBucket("address").fetch(
				orderObj.getO_SHIP_ADDR()).execute();
		Address o_ship_addr_id_json = (Address) GSON.fromJson(
				o_ship_addr_id_obj.getValueAsString(), Address.class);
		IRiakObject o_ship_addr_co_id_obj = getRiakIClient()
				.fetchBucket("country").execute()
				.fetch(o_ship_addr_id_json.getCountry_id() + "").execute();
		IRiakObject o_bill_addr_co_id_obj = getRiakIClient()
				.fetchBucket("country").execute()
				.fetch(o_bill_addr_id.getCountry_id() + "").execute();

	}

	/*
	 * Metodo que insere um order sem contexto de utilizaçao, também actualiza o
	 * last order de cada cliente e coloca a venda no buffer
	 */
	public void insertOrder(Order order, List<OrderLine> orderLines,
			CCXactItem ccXact) throws Exception {

		for (OrderLine ol : orderLines) {
			order.addOrderLine(ol);
		}
		getBucket("order")
				.store(order.getO_ID(), GSON.toJson(order).toString())
				.execute();

		for (OrderLine orderLine : orderLines) {
			Item item = GSON.fromJson(
					getBucket("item").fetch(orderLine.getOL_I_ID() + "")
							.execute().getValueAsString(), Item.class);
			int sold = item.getI_TOTAL_SOLD();
			sold += orderLine.OL_QTY;
			item.setI_TOTAL_SOLD(sold);
			// verificar se i_id a null
			BestSellerEntry bse = new BestSellerEntry(item.I_SUBJECT,
					item.I_ID, sold);

			getBucket("BestSellersBuff").store(item.getI_ID() + "",
					GSON.toJson(bse).toString()).execute();
			getBucket("item").store(item.getI_ID() + "",
					GSON.toJson(item).toString()).execute();
		}

		IRiakObject customerRiak = getBucket("customer").fetch(order.O_C_ID)
				.execute();
		Customer customer = (Customer) GSON.fromJson(
				customerRiak.getValueAsString(), Customer.class);
		customer.setC_O_LAST_ID(order.getO_ID());

		getBucket("customer").store(order.O_C_ID,
				GSON.toJson(customer).toString()).execute();

		getBucket("cc_xacts").store(order.getO_ID(), GSON.toJson(ccXact))
				.execute();

	}

	public void doSearch(String term, String field) throws Exception { // 30
		// TODO: Fazer a pesquisa no texto

		if (term.equalsIgnoreCase("SUBJECT")) {
			getBucket(field + "_" + "item_subject_index");

		} else if (term.equalsIgnoreCase("AUTHOR")) {
			getBucket(field + "_" + "item_author_index");

		} else if (term.equalsIgnoreCase("TITLE")) {
			getBucket(field + "_" + "item_title_index");

		} else {
			System.out.println("OPTION NOT RECOGNIZED");
		}
	}

	public void newProducts(String field) throws Exception {
		Iterable<String> it = getRawClient().listKeys(
				field + "_item_subject_index");
		Map<String, Map<String, Object>> results = new HashMap<String, Map<String, Object>>();
		for (String key : it) {
			getBucket("item").fetch(key).execute();
		}
	}

	public Map<String, Map<String, Map<String, Object>>> getResults()
			throws Exception {
		/*
		 * Map<String, Map<String, Object>> results = rangeQuery("results",
		 * null, 10000); // Parece que nos results estao itens e para cada chave
		 * faz-se o // seguinte processamento for (KeySlice key : keys) { if
		 * (!key.columns.isEmpty()) { String key_name = key.key; // for each
		 * client if (!results.containsKey(key_name)) { results.put(key_name,
		 * new TreeMap<String, Map<String, Object>>()); } for
		 * (ColumnOrSuperColumn c : key.getColumns()) { if
		 * (c.isSetSuper_column()) { String superColumn_name = null; // for each
		 * item try { superColumn_name = new String(c.getSuper_column()
		 * .getName(), "UTF-8"); } catch (UnsupportedEncodingException e) {
		 * e.printStackTrace(); // To change body of catch // statement use File
		 * | // Settings | File // Templates. } if (!results.get(key_name)
		 * .containsKey(superColumn_name)) {
		 * results.get(key_name).put(superColumn_name, new TreeMap<String,
		 * Object>()); } for (Column co : c.getSuper_column().columns) {
		 * results.get(key_name) .get(superColumn_name) .put(new
		 * String(co.getName()), BenchmarkUtil.toObject(co .getValue())); } } }
		 * }
		 * 
		 * }
		 * 
		 * return results;
		 */
		return null;
	}

	// Todos os nós processam as mesmas chaves. Errado :( [DISCTUIR]
	public void BestSellers(String subject) throws JsonSyntaxException,
			 RiakException {

		Map<String, BestSellerSubject> subjectBestSellers = new HashMap<String, BestSellerSubject>();
		Bucket bucket = getBucket("BestSellersBuff");
		//TODO: Este varrimento de keys provoca repetições. 
		Iterable<String> it = bucket.keys();
		BestSellerSubject orderedSubjectEntries;
		for (String key : it) {
			IRiakObject objRiak = getBucket("BestSellersBuff").fetch(key)
					.execute();
			if (objRiak == null)
				continue;
			BestSellerEntry bse = GSON.fromJson(objRiak.getValueAsString(),
					BestSellerEntry.class);
			getBucket("BestSellersBuff").delete(key).execute();
			if (!subjectBestSellers.containsKey(bse.I_SUBJECT)) {
				IRiakObject obj = getBucket("bestsellers").fetch(
						bse.getI_SUBJECT()).execute();
				if (obj == null) {
					orderedSubjectEntries = new BestSellerSubject();
				} else {
					orderedSubjectEntries = GSON.fromJson(
							obj.getValueAsString(), BestSellerSubject.class);
				}
				subjectBestSellers.put(bse.I_SUBJECT, orderedSubjectEntries);
			} else {
				orderedSubjectEntries = subjectBestSellers.get(bse.I_SUBJECT);
			}
			List<BestSellerEntry> entries = orderedSubjectEntries.getEntries();
			if (entries.size() == 0) {
				entries.add(bse);
			} else
				for (int i = 0; i < entries.size(); i++) {
					if (entries.get(i).getI_TOTAL_SOLD() <= bse
							.getI_TOTAL_SOLD()) {
						entries.add(i, bse);
						if (entries.size() > BESTSELLERMAX)
							entries.remove(entries.size() - 1);
						break;
					}
					if (i == entries.size() - 1
							&& entries.size() + 1 <= BESTSELLERMAX) {
						entries.add(i + 1, bse);
						break;
					}
				}
		}

		for (Entry<String, BestSellerSubject> entry : subjectBestSellers
				.entrySet()) {
			getBucket("bestsellers").store(entry.getKey(),
					GSON.toJson(entry.getValue())).execute();
		}

	}

	/*
	 * Obtem informações de um item
	 */
	public void ItemInfo(int id) throws Exception {
		IRiakObject obj = getBucket("item").fetch(id + "").execute();
		Item item = GSON.fromJson(obj.getValueAsString(), Item.class);
		IRiakObject obj2 = getBucket("author").fetch(item.I_A_ID + "")
				.execute();
		Author author = GSON.fromJson(obj2.getValueAsString(), Author.class);

	}

	/*
	 * obtem item Actualiza indice (insere este item no indice do subject e
	 * remove o item mais antigo) obtem 5 best sellers entre 10000 itens Altera
	 * atributos do item e armazena
	 */
	public void AdminChange(int item_id) throws Exception {

		Item item = (Item) GSON.fromJson(getBucket("item").fetch(item_id + "")
				.execute().getValueAsString(), Item.class);
		String dateString = item.getI_PUB_DATE();

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		java.util.Date date = formatter.parse(dateString);
		String subject = (String) item.getI_SUBJECT();
		int author_id = (Integer) item.getI_AUTHOR();
		String title = (String) item.getI_TITLE();

		updateIndex(subject, date, item_id, title, author_id);

		Map<String, Map<String, Object>> orders = rangeQuery("order", null,
				10000);

		Map<Integer, Integer> items_info = new TreeMap<Integer, Integer>();

		for (Map<String, Object> orders_info : orders.values()) {
			boolean found = false;
			Collection<OrderLine> orderLines = (Collection<OrderLine>) orders_info
					.get("orderLines");
			TreeMap<Integer, Integer> bought_items = new TreeMap<Integer, Integer>();
			for (OrderLine order_line : orderLines) {
				int i_id = (Integer) order_line.getOL_I_ID();
				if (i_id == item_id) {
					found = true;

				} else {
					int item_qty = (Integer) order_line.getOL_QTY();
					bought_items.put(i_id, item_qty);
				}
			}

			if (found == true) {
				for (Integer i_id : bought_items.keySet()) {
					if (items_info.containsKey(i_id)) {
						int current_qty = items_info.get(i_id);
						items_info.put(i_id,
								(bought_items.get(i_id) + current_qty));
					} else {
						items_info.put(i_id, bought_items.get(i_id));
					}
				}
			}
		}

		Map top_sellers = reverseSortByValue(items_info);

		List<Integer> best = new ArrayList<Integer>();
		int num = 0;
		for (Iterator<Integer> it = top_sellers.keySet().iterator(); it
				.hasNext();) {
			int key = it.next();
			best.add(key);
			num++;
			if (num == 5)
				break;
		}

		if (num < 5) {
			for (int i = num; i < 5; i++) {
				best.add(random.nextInt(990)); // the items are form 0 to 1000
												// right?
			}

		}

		item.setPubDate(new Date(System.currentTimeMillis()).toString());
		item.setI_IMAGE(new String("img" + random.nextInt(1000) % 100
				+ "/image_" + random.nextInt(1000) + ".gif"));
		item.setI_THUMBNAIL(new String("img" + random.nextInt(1000) % 100
				+ "/thumb" + random.nextInt(1000) + ".gif"));
		item.setI_RELATED1(best.get(0));
		item.setI_RELATED2(best.get(1));
		item.setI_RELATED3(best.get(2));
		item.setI_RELATED4(best.get(3));
		item.setI_RELATED5(best.get(4));
		getBucket("item").store(item_id + "", GSON.toJson(item).toString())
				.execute();
	}

	public Object readfromColumn(String key, String ColumnFamily,
			String column, int con) throws Exception {

		IRiakObject bucketObject = getBucket(ColumnFamily).fetch(key).execute();

		if (bucketObject == null)
			return null;
		Entity entity = (Entity) GSON.fromJson(bucketObject.getValueAsString(),
				getEntityClass(ColumnFamily));

		return entity.getValuesToInsert().get(column);

	}

	public void insert(Object value, String key, String column_family,
			String column, int writeConsistency) throws Exception {
		IRiakObject response = getBucket(column_family).fetch(key).execute();
		Entity entity;
		if (response != null && !response.getValue().equals("")) {
			entity = (Entity) GSON.fromJson(response.getValueAsString(),
					getEntityClass(column_family));
		} else {
			Class<?> entityClass = getEntityClass(column_family);
			Constructor<?> ct = entityClass.getConstructor(null);
			entity = (Entity) ct.newInstance(null);
		}
		insertOrModifyAttribute(entity, value, column, writeConsistency);
		getBucket(column_family).fetch(key).execute();
	}

	private Entity insertOrModifyAttribute(Entity entity, Object value,
			String column, int writeConsistency) throws Exception {

		Class<? extends Entity> cls = entity.getClass();
		Field fld = cls.getField(column);
		fld.set(entity, value);
		return entity;
	}

	public IRiakClient getRiakIClient() {
		boolean openClient = false;
		IRiakClient cl = null;

		while (!openClient) { // until there is one open

			if (!iclients.isEmpty()) { // if none, then null...
				cl = iclients.get(last);
				openClient = true;
				last++;
				last = last >= iclients.size() ? 0 : last;
			} else {
				openClient = true;
			}
		}

		return cl;
	}

	public RawClient getRawClient()  {

		boolean openClient = false;
		RawClient cl = null;

		while (!openClient) { // until there is one open

			if (!clients.isEmpty()) { // if none, then null... cl =
				cl = clients.get(lastRaw);
				openClient = true;
				lastRaw++;
				lastRaw = lastRaw >= clients.size() ? 0 : lastRaw;
			} else {
				openClient = true;
			}
		}

		if (cl == null) {
			System.out.println("Exception");
		
		}

		return cl;

	}

	public void modifyOrInsertListOfColumns(String key, String columnFamily,
			Map<String, Object> columnToValuesMap, int level)
			throws Exception {

		Entity entity;
		IRiakObject obj = getBucket(columnFamily).fetch(key).execute();
		if (obj != null) {
			entity = (Entity) GSON.fromJson(obj.getValueAsString(),
					getEntityClass(columnFamily));

		} else {
			entity = (Entity) GSON.fromJson("{}", getEntityClass(columnFamily));
		}

		for (Entry<String, Object> cols : columnToValuesMap.entrySet()) {
			insertOrModifyAttribute(entity, cols.getValue(), cols.getKey(),
					level);
		}

		getBucket(columnFamily).store(key,
				GSON.toJson(entity, getEntityClass(columnFamily)).toString())
				.execute();
	}

	// if columnToValueMap is empty remove key
	public void removeKeyOrColumn(String key, String bucket,
			List<String> columns, int level) throws Exception {

		if (columns == null) {
			getBucket(bucket).delete(key);
		} else {
			// TODO: else nao está feito. Analisar se é preciso fazer
			System.out.println("Nao devia entrar aqui");
			/*
			 * RiakObject obj = getRiakClient().fetch(bucket, key).getObject();
			 * Entity json = (Entity)new Gson().fromJson(obj.getValue(),
			 * getEntityClass(bucket);
			 * 
			 * for (String cols : columns) { json.remove(cols); }
			 * 
			 * obj.setValue(new Gson().toJson(json));
			 * getRiakClient().store(obj);
			 */
		}
	}

	private Class<?> getEntityClass(String string) {
		String className = string.substring(0, 1).toUpperCase()
				+ string.substring(1);
		try {
			return Class
					.forName("pt.fct.di.benchmarks.TPCW_Riak.entities."
							+ className);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	private Bucket getBucket(String bucketName)
			throws RiakRetryFailedException {
		Bucket bucket = getRiakIClient().fetchBucket(bucketName.toLowerCase())
				.execute();
		return bucket;
	}

	/*
	 * Recebe um assunto e um item insere o item no indice do assunto TODO:
	 * [DISCTUIR]Esta funçao devia ser chamada em mais sitios?
	 */
	public void updateIndex(String subject, java.util.Date date, int item_id,
			String title, int author_key) throws Exception {

		Author author = (Author) GSON.fromJson(
				getBucket("author").fetch(author_key + "").execute()
						.getValueAsString(), Author.class);

		AuthorIndex authorIndex = new AuthorIndex(author.getA_FNAME(),
				author.getA_LNAME(), title);

		Date d = new Date(System.currentTimeMillis());
		Long new_time_stamp = Long.MAX_VALUE - d.getTime();
		String new_index_key = new_time_stamp + "." + item_id;
		getBucket(subject + "_item_subject_index").store(new_index_key,
				GSON.toJson(authorIndex)).execute();
		// index(new_index_key, subject+"_item_subject_index", new_index_key,
		// authorIndex);

		// TODO: Isto não deve estar a funcionar, parece estranho
		Long old_time_stamp = Long.MAX_VALUE - date.getTime();
		String old_index_key = old_time_stamp + "." + item_id;
		remove(old_index_key, subject + "_item_subject_index", null);
	}

	static Map reverseSortByValue(Map map) {
		List list = new LinkedList(map.entrySet());
		Collections.sort(list, new Comparator() {
			public int compare(Object o1, Object o2) {
				return ((Comparable) ((Map.Entry) (o1)).getValue())
						.compareTo(((Map.Entry) (o2)).getValue());
			}
		});
		Collections.reverse(list);
		Map result = new LinkedHashMap();
		for (Iterator it = list.iterator(); it.hasNext();) {
			Map.Entry entry = (Map.Entry) it.next();
			result.put(entry.getKey(), entry.getValue());
		}
		return result;
	}

} public class Address implements Entity {


    public String ADDR_STREET1;
    public String ADDR_STREET2;
    public String ADDR_CITY;
    public String ADDR_STATE;
    public String ADDR_ZIP;
    public int ADDR_CO_ID;
    public String key;

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

        Random r = new Random();
        this.ADDR_STREET1 = street1;
        this.ADDR_STREET2 = street2;
        this.ADDR_CITY = city;
        this.ADDR_STATE = state;
        this.ADDR_ZIP = zip;
        this.ADDR_CO_ID = country;
        this.key = key;
    }

    public String getAddress_id() {
        return key;
    }

    public void setAddress_id(String ADDR_ID) {
        this.key = ADDR_ID;
    }

    public String getCity() {
        return ADDR_CITY;
    }

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

    public int getCountry_id() {
        return ADDR_CO_ID;
    }

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

    public String getState() {
        return ADDR_STATE;
    }

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

    public String getStreet1() {
        return ADDR_STREET1;
    }

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

    public String getStreet2() {
        return ADDR_STREET2;
    }

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

    public String getZip() {
        return ADDR_ZIP;
    }

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

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

        values.put("ADDR_STREET1", ADDR_STREET1);
        values.put("ADDR_STREET2", ADDR_STREET2);
        values.put("ADDR_CITY", ADDR_CITY);
        values.put("ADDR_STATE", ADDR_STATE);
        values.put("ADDR_ZIP", ADDR_ZIP);
        values.put("ADDR_CO_ID", ADDR_CO_ID);

        return values;
    }

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


} public class Author implements Entity {


	public String A_FNAME;
	public String A_LNAME;
	public String A_MNAME;
	public String A_BIO;
	public String A_DOB;
    public int A_ID;
    
    public Author(int id, String fname, String Lname, String mname, String dob, String bio){
    	this.A_ID = id;
    	A_FNAME = fname;
    	A_LNAME = Lname;
    	A_BIO = bio;
    	A_DOB = dob;
    	A_MNAME = mname;
    }

	public String getA_FNAME() {
		return A_FNAME;
	}

	public void setA_FNAME(String a_FNAME) {
		A_FNAME = a_FNAME;
	}

	public String getA_LNAME() {
		return A_LNAME;
	}

	public void setA_LNAME(String a_LNAME) {
		A_LNAME = a_LNAME;
	}

	public String getA_MNAME() {
		return A_MNAME;
	}

	public void setA_MNAME(String a_MNAME) {
		A_MNAME = a_MNAME;
	}

	public String getABIO() {
		return A_BIO;
	}

	public void setABIO(String aBIO) {
		A_BIO = aBIO;
	}

	public String getA_DOB() {
		return A_DOB;
	}

	public void setA_DOB(String A_DOB) {
		A_DOB = A_DOB;
	}

	public int getAuthor_id() {
		return A_ID;
	}

	public void setAuthor_id(int A_ID) {
		this.A_ID = A_ID;
	}

	@Override
	public String getKeyName() {
		return "A_ID";
	}

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

	        values.put("A_FNAME", A_FNAME);
	        values.put("A_LNAME", A_LNAME);
	        values.put("A_MNAME", A_MNAME);
	        values.put("A_DOB", A_DOB);
	        values.put("A_BIO", A_BIO);

	        return values;
	    }


    

} public class CCXactItem implements Entity {


	public  String CX_O_ID;
	public String CX_TYPE;
	public long CX_CC_NUM;
	public  String CX_CC_NAME;
	public String CX_CC_EXPIRY;
	/* String authId;*/
	public  double CX_XACT_AMT;
	public  String CX_XACT_DATE;
	public  int CX_CO_ID;
	


	

    public CCXactItem(String type, long num, String name, String expiry, double total, String shipDate, String order, int country) {

        this.CX_O_ID = order;
        this.CX_TYPE = type;
        this.CX_CC_NUM = num;
        this.CX_CC_NAME = name;
        this.CX_CC_EXPIRY = expiry;
        this.CX_XACT_AMT = total;
        this.CX_XACT_DATE = shipDate;
        this.CX_CO_ID = country;
    }
    public String getCX_O_ID() {
		return CX_O_ID;
	}

	public void setCX_O_ID(String cx_id) {
		this.CX_O_ID = cx_id;
	}
    public int getCountry() {
        return CX_CO_ID;
    }

    public void setCountry(int country) {
        this.CX_CO_ID = country;
    }

    public String getExpiry() {
        return CX_CC_EXPIRY;
    }

    public void setExpiry(String expiry) {
        this.CX_CC_EXPIRY = expiry;
    }

    public String getName() {
        return CX_CC_NAME;
    }

    public void setName(String name) {
        this.CX_CC_NAME = name;
    }

    public long getNum() {
        return CX_CC_NUM;
    }

    public void setNum(long num) {
        this.CX_CC_NUM = num;
    }

    public String getShipDate() {
        return CX_XACT_DATE;
    }

    public void setShipDate(String shipDate) {
        this.CX_XACT_DATE = shipDate;
    }

    public double getTotal() {
        return CX_XACT_AMT;
    }

    public void setTotal(double total) {
        this.CX_XACT_AMT = total;
    }

    public String getType() {
        return CX_TYPE;
    }

    public void setType(String type) {
        this.CX_TYPE = type;
    }

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

        values.put("CX_TYPE", CX_TYPE);
        values.put("CX_CC_NUM", CX_CC_NUM);
        values.put("CX_CC_NAME", CX_CC_NAME);
        values.put("CX_CC_EXPIRY", CX_CC_EXPIRY);
        values.put("CX_XACT_DATE", CX_XACT_DATE);
        values.put("CX_XACT_AMT", CX_XACT_AMT);
        values.put("CX_CO_ID", CX_CO_ID);
        values.put("CX_O_ID", CX_O_ID);

        return values;
    }

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


} public class Country implements Entity {

	public String CO_NAME;
	public String CO_CURRENCY;
	public double CO_EXCHANGE;
	public int CO_ID;

	public Country(int co_id, String name, String currency, double exchange) {
		this.CO_NAME = name;
		this.CO_CURRENCY = currency;
		this.CO_EXCHANGE = exchange;
		this.CO_ID = co_id;
	}

	public String getCo_id() {
		return CO_NAME;
	}

	public String getCurrency() {
		return CO_CURRENCY;
	}

	public void setCurrency(String currency) {
		this.CO_CURRENCY = currency;
	}

	public double getExchange() {
		return CO_EXCHANGE;
	}

	public void setExchange(double exchange) {
		this.CO_EXCHANGE = exchange;
	}

	public String getName() {
		return CO_NAME;
	}

	public void setName(String name) {
		this.CO_NAME = name;
	}

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

		values.put("CO_NAME", CO_NAME);
		values.put("CO_CURRENCY", CO_CURRENCY);
		values.put("CO_EXCHANGE", CO_EXCHANGE);
		values.put("CO_ID", CO_ID);

		return values;
	}

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

} public class Customer implements Entity {

	public String c_id;
	public String C_UNAME, C_PASSWD, C_LNAME, C_FNAME;
	public String C_PHONE;
	public String C_EMAIL;
	public String C_SINCE;
	public String C_LAST_VISIT;
	public String C_LOGIN;
	public String C_EXPIRATION;
	public double C_BALANCE;

	public String getC_O_LAST_ID() {
		return C_O_LAST_ID;
	}

	public void setC_O_LAST_ID(String c_O_LAST_ID) {
		C_O_LAST_ID = c_O_LAST_ID;
	}

	public double C_YTD_PMT;
	public String C_BIRTHDATE;
	public String C_DATA;
	public double C_DISCOUNT;
	public String C_ADDR_ID;
	public String C_O_LAST_ID;

	public Customer() {
	}

	public Customer(String C_ID, String C_UNAME, String C_PASSWD,
			String C_LNAME, String C_FNAME, String C_PHONE, String C_EMAIL,
			String since, String lastLogin, String login, String expiration,
			double balance, double ytd_pmt, String birthdate, String data,
			double C_DISCOUNT, String 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.C_SINCE = since;
		this.C_LAST_VISIT = lastLogin;
		this.C_LOGIN = login;
		this.C_EXPIRATION = expiration;
		this.C_BALANCE = balance;
		this.C_YTD_PMT = ytd_pmt;
		this.C_BIRTHDATE = birthdate;
		this.C_DATA = data;
		this.C_DISCOUNT = C_DISCOUNT;
		this.C_ADDR_ID = 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 getAddress() {
		return C_ADDR_ID;
	}

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

	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 double getBalance() {
		return C_BALANCE;
	}

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

	public String getBirthdate() {
		return C_BIRTHDATE;
	}

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

	public String getC_id() {
		return c_id;
	}

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

	public String getData() {
		return C_DATA;
	}

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

	public String getExpiration() {
		return C_EXPIRATION;
	}

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

	public String getLastLogin() {
		return C_LAST_VISIT;
	}

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

	public String getLogin() {
		return C_LOGIN;
	}

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

	public String getSince() {
		return C_SINCE;
	}

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

	public double getYtd_pmt() {
		return C_YTD_PMT;
	}

	public void setYtd_pmt(double ytd_pmt) {
		this.C_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", C_ADDR_ID);
		values.put("C_PHONE", C_PHONE);
		values.put("C_EMAIL", C_EMAIL);
		values.put("C_SINCE", C_SINCE);
		values.put("C_LAST_VISIT", C_LAST_VISIT);
		values.put("C_LOGIN", C_LOGIN);
		values.put("C_EXPIRATION", C_EXPIRATION);
		values.put("C_DISCOUNT", C_DISCOUNT);
		values.put("C_BALANCE", C_BALANCE);
		values.put("C_YTD_PMT", C_YTD_PMT);
		values.put("C_BIRTHDATE", C_BIRTHDATE);
		values.put("C_DATA", C_DATA);
		values.put("C_O_LAST_ID", C_O_LAST_ID);

		return values;
	}

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

} public class Item implements Entity {

	public int I_ID; // ID
	public String I_TITLE;
	public String I_PUB_DATE;
	public int I_A_ID;
	public String I_PUBLISHER;
	public String I_DESC;
	public String I_SUBJECT;
	public String I_THUMBNAIL;
	public String I_IMAGE;
	public double I_COST;
	public int I_STOCK;
	public String I_ISBN;// international id
	public double I_SRP;// Suggested Retail Price
	public int I_RELATED1;
	public int I_RELATED2;
	public int I_RELATED3;
	public int I_RELATED4;
	public int I_RELATED5;
	public int I_PAGE;
	public int I_TOTAL_SOLD;
	public String I_AVAIL; // Data when available
	public String I_BACKING;
	public String I_DIMENSION;

	public Item(int i_id, String I_TITLE, String pubDate, String I_PUBLISHER,
			String I_DESC, String I_SUBJECT, String thumbnail, String image,
			double I_COST, int I_STOCK, String isbn, double srp,
			int I_RELATED1, int I_RELATED2, int I_RELATED3, int I_RELATED4,
			int I_RELATED5, int I_PAGE, String avail, String I_BACKING,
			String dimensions, int author) {
		this.I_ID = i_id;
		this.I_TITLE = I_TITLE;
		this.I_PUB_DATE = pubDate;
		this.I_A_ID = author;
		this.I_PUBLISHER = I_PUBLISHER;
		this.I_DESC = I_DESC;
		this.I_SUBJECT = I_SUBJECT;
		this.I_THUMBNAIL = thumbnail;
		this.I_IMAGE = image;
		this.I_COST = I_COST;
		this.I_STOCK = I_STOCK;
		this.I_ISBN = isbn;
		this.I_SRP = srp;
		this.I_RELATED1 = I_RELATED1;
		this.I_RELATED2 = I_RELATED2;
		this.I_RELATED3 = I_RELATED3;
		this.I_RELATED4 = I_RELATED4;
		this.I_RELATED5 = I_RELATED5;
		this.I_PAGE = I_PAGE;
		this.I_AVAIL = avail;
		this.I_BACKING = I_BACKING;
		this.I_DIMENSION = dimensions;

	}

	public int getI_AUTHOR() {
		return I_A_ID;
	}

	public void setI_AUTHOR(int i_AUTHOR) {
		I_A_ID = i_AUTHOR;
	}

	public String getI_BACKING() {
		return I_BACKING;
	}

	public void setI_BACKING(String I_BACKING) {
		this.I_BACKING = I_BACKING;
	}

	public double getI_COST() {
		return I_COST;
	}

	public void setI_COST(double i_COST) {
		I_COST = i_COST;
	}

	public String getI_DESC() {
		return I_DESC;
	}

	public void setI_DESC(String I_DESC) {
		this.I_DESC = I_DESC;
	}

	public int getI_PAGE() {
		return I_PAGE;
	}

	public void setI_PAGE(int I_PAGE) {
		this.I_PAGE = I_PAGE;
	}

	public String getI_PUBLISHER() {
		return I_PUBLISHER;
	}

	public void setI_PUBLISHER(String I_PUBLISHER) {
		this.I_PUBLISHER = I_PUBLISHER;
	}

	public int getI_STOCK() {
		return I_STOCK;
	}

	public void setI_STOCK(int i_STOCK) {
		I_STOCK = i_STOCK;
	}

	public String getI_SUBJECT() {
		return I_SUBJECT;
	}

	public void setI_SUBJECT(String I_SUBJECT) {
		this.I_SUBJECT = I_SUBJECT;
	}

	public String getI_TITLE() {
		return I_TITLE;
	}

	public void setI_TITLE(String I_TITLE) {
		this.I_TITLE = I_TITLE;
	}

	public String getAvail() {
		return I_AVAIL;
	}

	public void setAvail(String avail) {
		this.I_AVAIL = avail;
	}

	public String getDimensions() {
		return I_DIMENSION;
	}

	public void setDimensions(String dimensions) {
		this.I_DIMENSION = dimensions;
	}

	public int getI_id() {
		return I_ID;
	}

	public void setI_id(int i_id) {
		this.I_ID = i_id;
	}

	public String getImage() {
		return I_IMAGE;
	}

	public void setImage(String image) {
		this.I_IMAGE = image;
	}

	public String getIsbn() {
		return I_ISBN;
	}

	public void setIsbn(String isbn) {
		this.I_ISBN = isbn;
	}

	public String getPubDate() {
		return I_PUB_DATE;
	}

	public void setPubDate(String pubDate) {
		this.I_PUB_DATE = pubDate;
	}

	public double getI_SRP() {
		return I_SRP;
	}

	public void setSrp(double srp) {
		this.I_SRP = srp;
	}

	public String getThumbnail() {
		return I_THUMBNAIL;
	}

	public void setThumbnail(String thumbnail) {
		this.I_THUMBNAIL = thumbnail;
	}

	public TreeMap<String, Object> getValuesToInsert() {

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

		values.put("I_TITLE", I_TITLE);
		values.put("I_A_ID", I_A_ID);
		values.put("I_PUB_DATE", I_PUB_DATE);
		values.put("I_PUBLISHER", I_PUBLISHER);
		values.put("I_SUBJECT", I_SUBJECT);
		values.put("I_DESC", I_DESC);
		values.put("I_RELATED1", I_RELATED1);
		values.put("I_RELATED2", I_RELATED2);
		values.put("I_RELATED3", I_RELATED3);
		values.put("I_RELATED4", I_RELATED4);
		values.put("I_RELATED5", I_RELATED5);
		values.put("I_THUMBNAIL", I_THUMBNAIL);
		values.put("I_IMAGE", I_IMAGE);
		values.put("I_SRP", I_SRP);
		values.put("I_COST", I_COST);
		values.put("I_AVAIL", I_AVAIL);
		values.put("I_STOCK", I_STOCK);
		values.put("I_ISBN", I_ISBN);
		values.put("I_PAGE", I_PAGE);
		values.put("I_BACKING", I_BACKING);
		values.put("I_DIMENSION", I_DIMENSION);
		values.put("I_ID", I_ID);

		return values;
	}

	public String getKeyName() {
		return "I_ID";
	}
	
	public String getI_PUB_DATE() {
		return I_PUB_DATE;
	}

	public void setI_PUB_DATE(String i_PUB_DATE) {
		I_PUB_DATE = i_PUB_DATE;
	}

	public int getI_ID() {
		return I_ID;
	}

	public void setI_ID(int i_ID) {
		I_ID = i_ID;
	}

	public int getI_A_ID() {
		return I_A_ID;
	}

	public void setI_A_ID(int i_A_ID) {
		I_A_ID = i_A_ID;
	}

	public String getI_THUMBNAIL() {
		return I_THUMBNAIL;
	}

	public void setI_THUMBNAIL(String i_THUMBNAIL) {
		I_THUMBNAIL = i_THUMBNAIL;
	}

	public String getI_IMAGE() {
		return I_IMAGE;
	}

	public void setI_IMAGE(String i_IMAGE) {
		I_IMAGE = i_IMAGE;
	}

	public String getI_ISBN() {
		return I_ISBN;
	}

	public void setI_ISBN(String i_ISBN) {
		I_ISBN = i_ISBN;
	}

	public int getI_RELATED1() {
		return I_RELATED1;
	}

	public void setI_RELATED1(int i_RELATED1) {
		I_RELATED1 = i_RELATED1;
	}

	public int getI_RELATED2() {
		return I_RELATED2;
	}

	public void setI_RELATED2(int i_RELATED2) {
		I_RELATED2 = i_RELATED2;
	}

	public int getI_RELATED3() {
		return I_RELATED3;
	}

	public void setI_RELATED3(int i_RELATED3) {
		I_RELATED3 = i_RELATED3;
	}

	public int getI_RELATED4() {
		return I_RELATED4;
	}

	public void setI_RELATED4(int i_RELATED4) {
		I_RELATED4 = i_RELATED4;
	}

	public int getI_RELATED5() {
		return I_RELATED5;
	}

	public void setI_RELATED5(int i_RELATED5) {
		I_RELATED5 = i_RELATED5;
	}

	public String getI_AVAIL() {
		return I_AVAIL;
	}

	public void setI_AVAIL(String i_AVAIL) {
		I_AVAIL = i_AVAIL;
	}

	public String getI_DIMENSION() {
		return I_DIMENSION;
	}

	public void setI_DIMENSION(String i_DIMENSION) {
		I_DIMENSION = i_DIMENSION;
	}

	public void setI_SRP(double i_SRP) {
		I_SRP = i_SRP;
	}

	public int getI_TOTAL_SOLD() {
		return I_TOTAL_SOLD;
	}

	public void setI_TOTAL_SOLD(int i_TOTAL_SOLD) {
		I_TOTAL_SOLD = i_TOTAL_SOLD;
	}

	

} public class Order implements Entity {

	public String O_ID;
	public String O_C_ID; // Customer customer?
	public String O_DATE;
	public double O_SUB_TOTAL;
	public Collection<OrderLine> orderLines;

	public Order() {
		orderLines = new ArrayList<OrderLine>();
	}

	public void addOrderLine(OrderLine ol) {
		if (orderLines == null)
			orderLines = new ArrayList<OrderLine>();
		orderLines.add(ol);
	}

	public OrderLine getOrderLine(String id) {
		for (OrderLine o : orderLines) {
			if (o.getOL_ID().equals(id))
				return o;
		}
		return null;
	}

	public String getO_DATE() {
		return O_DATE;
	}

	public void setO_DATE(String o_DATE) {
		O_DATE = o_DATE;
	}

	public double getO_SUB_TOTAL() {
		return O_SUB_TOTAL;
	}

	public void setO_SUB_TOTAL(double o_SUB_TOTAL) {
		O_SUB_TOTAL = o_SUB_TOTAL;
	}

	public double getO_TAX() {
		return O_TAX;
	}

	public void setO_TAX(double o_TAX) {
		O_TAX = o_TAX;
	}

	public double getO_TOTAL() {
		return O_TOTAL;
	}

	public void setO_TOTAL(double o_TOTAL) {
		O_TOTAL = o_TOTAL;
	}

	public String getO_SHIP_TYPE() {
		return O_SHIP_TYPE;
	}

	public void setO_SHIP_TYPE(String o_SHIP_TYPE) {
		O_SHIP_TYPE = o_SHIP_TYPE;
	}

	public String getO_SHIP_DATE() {
		return O_SHIP_DATE;
	}

	public void setO_SHIP_DATE(String o_SHIP_DATE) {
		O_SHIP_DATE = o_SHIP_DATE;
	}

	public String getO_STATUS() {
		return O_STATUS;
	}

	public void setO_STATUS(String o_STATUS) {
		O_STATUS = o_STATUS;
	}

	public String getO_BILL_ADDR_ID() {
		return O_BILL_ADDR_ID;
	}

	public void setO_BILL_ADDR_ID(String o_BILL_ADDR_ID) {
		O_BILL_ADDR_ID = o_BILL_ADDR_ID;
	}

	public String getO_SHIP_ADDR() {
		return O_SHIP_ADDR_ID;
	}

	public void setO_SHIP_ADDR(String o_SHIP_ADDR) {
		O_SHIP_ADDR_ID = o_SHIP_ADDR;
	}

	public void setO_ID(String o_ID) {
		O_ID = o_ID;
	}

	public void setO_C_ID(String o_C_ID) {
		O_C_ID = o_C_ID;
	}

	public double O_TAX;
	public double O_TOTAL;
	public String O_SHIP_TYPE;
	public String O_SHIP_DATE;
	public String O_STATUS;
	public String O_BILL_ADDR_ID;
	public String O_SHIP_ADDR_ID;

	public Order(String O_ID, String O_C_ID, String O_DATE, double O_SUB_TOTAL,
			double O_TAX, double O_TOTAL, String O_SHIP_TYPE, String shipDate,
			String O_STATUS, String billAddress, String O_SHIP_ADDR) {
		this.O_ID = O_ID;
		this.O_C_ID = O_C_ID;
		this.O_DATE = O_DATE;
		this.O_SUB_TOTAL = O_SUB_TOTAL;
		this.O_TAX = O_TAX;
		this.O_TOTAL = O_TOTAL;
		this.O_SHIP_TYPE = O_SHIP_TYPE;
		this.O_SHIP_DATE = shipDate;
		this.O_STATUS = O_STATUS;
		this.O_BILL_ADDR_ID = billAddress;
		this.O_SHIP_ADDR_ID = O_SHIP_ADDR;
	}

	public TreeMap<String, Object> getValuesToInsert() {

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

		values.put("O_C_ID", O_C_ID);
		values.put("O_DATE", O_DATE);
		values.put("O_SUB_TOTAL", O_SUB_TOTAL);
		values.put("O_TAX", O_TAX);
		values.put("O_TOTAL", O_TOTAL);

		values.put("O_SHIP_TYPE", O_SHIP_TYPE);
		values.put("O_SHIP_DATE", O_SHIP_DATE);

		values.put("O_BILL_ADDR_ID", O_BILL_ADDR_ID);
		values.put("O_SHIP_ADDR_ID", O_SHIP_ADDR_ID);

		values.put("O_STATUS", O_STATUS);

		values.put("O_ID", O_ID);
		
		values.put("orderLines", orderLines);

		return values;
	}

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

	public String getO_ID() {
		return O_ID;
	}

	public String getO_C_ID() {
		return O_C_ID;
	}
} public class OrderLine implements Entity {

	public  String OL_ID;
	public  String OL_O_ID;
	public  int OL_I_ID;
	public  int OL_QTY;
	public  double OL_DISCOUNT;
	public  String OL_COMMENT;


    public OrderLine(String OL_ID, String OL_O_ID, int OL_I_ID, int OL_QTY, double OL_DISCOUNT, String OL_COMMENT) {
        this.OL_ID = OL_ID;
        this.OL_O_ID = OL_O_ID;
        this.OL_I_ID = OL_I_ID;
        this.OL_QTY = OL_QTY;
        this.OL_DISCOUNT = OL_DISCOUNT;
        this.OL_COMMENT = OL_COMMENT;
    }

    public TreeMap<String, Object> getValuesToInsert() {

        TreeMap<String, Object> values = new TreeMap<String, Object>();
        values.put("OL_ID", OL_ID);
        values.put("OL_O_ID", OL_O_ID);
        values.put("OL_I_ID", OL_I_ID);
        values.put("OL_QTY", OL_QTY);
        values.put("OL_DISCOUNT", OL_DISCOUNT);
        values.put("OL_COMMENT", OL_COMMENT);

        return values;

    }

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

    public String getOL_ID() {
        return OL_ID;
    }
    
    public String getOL_O_ID() {
		return OL_O_ID;
	}

	public void setOL_O_ID(String oL_O_ID) {
		OL_O_ID = oL_O_ID;
	}

	public int getOL_I_ID() {
		return OL_I_ID;
	}

	public void setOL_I_ID(int oL_I_ID) {
		OL_I_ID = oL_I_ID;
	}

	public int getOL_QTY() {
		return OL_QTY;
	}

	public void setOL_QTY(int oL_QTY) {
		OL_QTY = oL_QTY;
	}

	public double getOL_DISCOUNT() {
		return OL_DISCOUNT;
	}

	public void setOL_DISCOUNT(double oL_DISCOUNT) {
		OL_DISCOUNT = oL_DISCOUNT;
	}

	public String getOL_COMMENT() {
		return OL_COMMENT;
	}

	public void setOL_COMMENT(String oL_COMMENT) {
		OL_COMMENT = oL_COMMENT;
	}

	public void setOL_ID(String oL_ID) {
		OL_ID = oL_ID;
	}
}
import org.uminho.gsd.benchmarks.generic.Constants;
import org.uminho.gsd.benchmarks.generic.helpers.NodeKeyGenerator;
import org.uminho.gsd.benchmarks.dataStatistics.ResultHandler;
import org.uminho.gsd.benchmarks.helpers.BenchmarkUtil;
import org.uminho.gsd.benchmarks.interfaces.Entity;
import org.uminho.gsd.benchmarks.interfaces.executor.AbstractDatabaseExecutorFactory;
import org.uminho.gsd.benchmarks.interfaces.executor.DatabaseExecutorInterface;
import org.uminho.gsd.benchmarks.interfaces.populator.AbstractBenchmarkPopulator;
import pt.fct.di.benchmarks.TPCW_Riak.database.TPCW_Riak_Executor;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Address;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Author;
import pt.fct.di.benchmarks.TPCW_Riak.entities.CCXactItem;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Country;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Customer;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Item;
import pt.fct.di.benchmarks.TPCW_Riak.entities.Order;
import pt.fct.di.benchmarks.TPCW_Riak.entities.OrderLine;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
				"Dollars", "Franc", "Pesos", "Yuan Renmimbi", "Dollars",
				"Pesos", "Kuna", "Pesos", "Pounds", "Koruna", "Kroner",
				"Pesos", "Dollars", "Sucre", "Pounds", "Colon", "Kroon",
				"Birr", "Pound", "Krone", "Dollars", "Markka", "Franc",
				"Pound", "Drachmas", "Dollars", "Dollars", "Forint", "Krona",
				"Rupees", "Rupiah", "Rial", "Dinar", "Punt", "Shekels",
				"Dollars", "Dinar", "Tenge", "Dinar", "Pounds", "Francs",
				"Ringgit", "Pesos", "Rupees", "Dollars", "Kroner", "Rupees",
				"Pesos", "Zloty", "Escudo", "Leu", "Rubles", "Riyal",
				"Dollars", "Koruna", "Rand", "Won", "Pesetas", "Dinar",
				"Krona", "Dollars", "Baht", "Dollars", "Lira", "Bolivar",
				"Kwacha" };

		if (numCountries > countriesNames.length) {
			numCountries = countriesNames.length - 1;
		}

		System.out.println(">>Inserting " + numCountries
				+ " countries || populatores " + num_threads);

		for (int i = 0; i < numCountries; i++) {

			// Country name = key
			// insert(exchanges[i], countriesNames[i], "Countries",
			// "CO_EXCHANGE", writeConsitency);
			// insert(currencies[i], countriesNames[i], "Countries",
			// "CO_CURRENCY", writeConsitency);

			Country country = new Country(i, countriesNames[i], currencies[i],
					exchanges[i]);
			try {
				databaseInsert(client, "INSERT_Countries", i + "", "country",
						country, results);
			} catch (Exception e) {
				e.printStackTrace();
				client_error = true;
				break;
			}
			this.countries.add(i);
		}
		if (debug) {
			System.out.println("Countries:" + countriesNames.length
					+ " inserted");
		}
	}

	/**
	 * **************** Order and XACTS * ******************
	 */
	public void insertOrder_and_CC_XACTS(int n) throws InterruptedException {

		int threads = num_threads;
		int sections = n;
		int firstSection = 0;

		if (n < num_threads) {
			threads = 1;
			firstSection = n;
		} else {
			sections = (int) Math.floor(n / num_threads);
			int rest = n - (num_threads * sections);
			firstSection = sections + rest;
		}

		System.out.println(">>Inserting " + n + " Orders || populatores "
				+ num_threads);

		barrier = new CountDownLatch(threads);

		Order_and_XACTSPopulator[] partial_orders = new Order_and_XACTSPopulator[threads];
		for (int i = threads; i > 0; i--) {

			int base = (threads - i); // /code copy form above constructors, if
										// reactivated please revise

			Order_and_XACTSPopulator populator = null;
			if (i == 0) {
				populator = new Order_and_XACTSPopulator(firstSection, base);

			} else {
				populator = new Order_and_XACTSPopulator(sections, base);
			}
			partial_orders[threads - i] = populator;
			Thread t = new Thread(populator, "Order populator" + (threads - i));
			t.start();
		}
		barrier.await();

		System.out.println("END");

		for (Order_and_XACTSPopulator populator : partial_orders) {
			results.addResults(populator.returnResults());
			populator.partial_results.cleanResults();
			populator = null;
		}
		System.gc();

	}

	class Order_and_XACTSPopulator implements Runnable {

		int num_orders;
		int base = 0;
		DatabaseExecutorInterface client;
		ResultHandler partial_results;

		public Order_and_XACTSPopulator(int num_orders, int base) {
			client = databaseClientFactory.getDatabaseClient();
			this.num_orders = num_orders;
			partial_results = new ResultHandler("", rounds);
			this.base = base;
		}

		public void run() {
			this.insertOrder_and_CC_XACTS(num_orders);
		}

		public void databaseInsert(Order order, List<OrderLine> orderLines,
				pt.fct.di.benchmarks.TPCW_Riak.entities.CCXactItem ccXact)
				throws Exception {
			((TPCW_Riak_Executor) client).insertOrder(order, orderLines, ccXact);