public class TranslationServerSide extends TranslationShared
		implements IsSerializable, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6786263404467413690L;
	public static int phraseumAlpha = 3;
	public static boolean localApertiumShowUnknown = true;

	public static String phraseumBin;
	public static String phraseumData;
	public static String dictionariumBin;
	public static String dictionariumData;

	public TranslationOutput translationService(TranslationInput input, SessionShared session)
			throws ForecatException {

		int currentId = 1;
		Object aux = session.getAttribute("SuggestionId");
		if (aux != null) {
			currentId = (Integer) aux;
		}

		session.setAttribute("translation", input);

		@SuppressWarnings("unchecked")
		List<LanguagesInput> languagesInput = (List<LanguagesInput>) session
				.getAttribute("engines");
		if (languagesInput == null) {
			throw new ForecatException("engines could not be obtained from session");
		}

		@SuppressWarnings("unchecked")
		List<LanguagesOutput> languagesOutput = (List<LanguagesOutput>) session
				.getAttribute("languages");
		if (languagesOutput == null) {
			throw new ForecatException("languages could not be obtained from session");
		}

		final Map<String, List<SourceSegment>> segmentPairs = new HashMap<String, List<SourceSegment>>();
		final Map<String, Integer> segmentCounts = new HashMap<String, Integer>();

		session.setAttribute("segmentPairs", segmentPairs);
		session.setAttribute("segmentCounts", segmentCounts);

		String[] words = slice(input.getSourceText());
		List<SourceSegment> sourceSegments = sliceIntoSegments(words, input.getMaxSegmentLenth(),
				input.getMinSegmentLenth(), currentId);

		session.setAttribute("SuggestionId", sourceSegments.size() + currentId);

		translateApertiumAPY(sourceSegments, input.getSourceCode(), input.getTargetCode(),
				segmentPairs, segmentCounts, languagesInput, languagesOutput);
		translateApertiumLocalInstallation(sourceSegments, input.getSourceCode(),
				input.getTargetCode(), segmentPairs, segmentCounts, languagesInput,
				languagesOutput);
		translateBingAPI(sourceSegments, input.getSourceCode(), input.getTargetCode(), segmentPairs,
				segmentCounts, languagesInput, languagesOutput);
		translateCachetrans(sourceSegments, input.getSourceCode(), input.getTargetCode(),
				segmentPairs, segmentCounts, languagesInput, languagesOutput);
		translateDictionarium(sourceSegments, input.getSourceCode(), input.getTargetCode(),
				segmentPairs, segmentCounts, languagesInput, languagesOutput);
		translatePhraseum(sourceSegments, input.getSourceCode(), input.getTargetCode(),
				segmentPairs, segmentCounts, languagesInput, languagesOutput);

		TranslationOutput output = new TranslationOutput(segmentPairs.size(), words.length);
		return output;
	}

	protected void translateApertiumAPI(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) {

		int pos;

		// Use this engine it if was in Languages input and the engine supports the requested
		// language pair:
		if (((pos = LanguagesInput.searchEngine(languagesInput, Engine.APERTIUM.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.APERTIUM.toString(), sourceCode, targetCode))) {
			String key = languagesInput.get(pos).getKey();

			try {
				String url = "http://api.apertium.org/json/translate";
				WebResource wr = Client.create().resource(url);

				Iterator<SourceSegment> it = sourceSegments.iterator();
				MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
				// TODO: make multiple requests to the server
				while (it.hasNext()) {
					queryParams.add("q", it.next().getSourceSegmentText());
				}
				queryParams.add("langpair", sourceCode + "|" + targetCode);
				queryParams.add("key", key);
				wr = wr.queryParams(queryParams);

				// GET request:
				// String response = wr.get(String.class);

				// POST request:
				String response = wr.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
						.post(String.class, queryParams);

				ObjectMapper mapper = new ObjectMapper();
				JsonNode rootNode = mapper.readValue(response, JsonNode.class);

				for (int i = 0, n = sourceSegments.size(); i < n; ++i) {
					String targetText = rootNode.get("responseData").get(i).get("responseData")
							.get("translatedText").asText();
					if (rootNode.get("responseData").get(i).get("responseStatus").asText()
							.equals("200")) {
						addSegments(segmentPairs, segmentCounts, targetText,
								Engine.APERTIUM.toString(), sourceSegments.get(i));
					}
				}
			} catch (JsonMappingException e) {
				// TODO: decide whether to throw the Forecat exception or simply return and move to
				// the next translation service
				return;
			} catch (JsonParseException e) {
				return;
			} catch (IOException e) {
				return;
			}
		}
	}

	protected void translateApertiumAPY(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) {

		int pos;

		// Use this engine it if was in Languages input and the engine supports the requested
		// language pair:
		if (((pos = LanguagesInput.searchEngine(languagesInput, Engine.APERTIUM.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.APERTIUM.toString(), sourceCode, targetCode))) {
			// String key = languagesInput.get(pos).getKey();

			try {
				String url = "http://apy.projectjj.com/translate?";
				WebResource wr = Client.create().resource(url);

				Iterator<SourceSegment> it = sourceSegments.iterator();
				MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl();
				queryParams.add("langpair", sourceCode + "|" + targetCode);

				// queryParams.add("key", key);

				String toTranslate = "";
				int index = 0;
				while (it.hasNext()) {
					SourceSegment ss = it.next();
					toTranslate += "<apertium-notrans>" + index + "</apertium-notrans>"
							+ ss.getSourceSegmentText() + "<br>";
					index++;
				}
				queryParams.add("q", toTranslate);

				wr = wr.queryParams(queryParams);

				// GET request:
				// String response = wr.get(String.class);

				// POST request:
				String response = wr.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
						.post(String.class, queryParams);

				ObjectMapper mapper = new ObjectMapper();
				JsonNode rootNode = mapper.readValue(response, JsonNode.class);

				// System.out.println(wr.getURI());
				// System.out.println(response);

				if (rootNode.get("responseStatus").asText().equals("200")) {
					String[] segments = rootNode.get("responseData").get("translatedText").asText()
							.split("<br>");
					for (String s : segments) {
						if (s.equals("")) {
							continue;
						}
						String[] parts = s.split("</apertium-notrans>");
						String targetText = parts[1];
						int position = Integer.parseInt(parts[0].split("<apertium-notrans>")[1]);

						addSegments(segmentPairs, segmentCounts, targetText,
								Engine.APERTIUM.toString(), sourceSegments.get(position));

						// System.out.println(sourceSegments.get(position).getSourceSegmentText()
						// + " " + targetText);
					}
				}

			} catch (JsonMappingException e) {
				// TODO: decide whether to throw the Forecat exception or simply return and move to
				// the next translation service
				e.printStackTrace();
				return;
			} catch (JsonParseException e) {
				return;
			} catch (IOException e) {
				return;
			}
		}
	}

	public void translateBingAPI(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) throws ForecatException {

		int pos;

		// Use this engine it if was in Languages input and the engine supports the requested
		// language pair:
		if (((pos = LanguagesInput.searchEngine(languagesInput, Engine.BING.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.BING.toString(), sourceCode, targetCode))) {
			// Client ID and client secret are separated by the first comma:
			String[] s = languagesInput.get(pos).getKey().split(",", 2);

			if (s.length != 2) {
				throw new ForecatException(
						"TranslationServer: wrong formatted id and secret for Bing");
			}
			Translate.setClientId(s[0]);
			Translate.setClientSecret(s[1]);

			String[] sourceTexts = new String[sourceSegments.size()];
			for (int i = 0, n = sourceSegments.size(); i < n; ++i) {
				sourceTexts[i] = sourceSegments.get(i).getSourceSegmentText();
			}

			// Call the translate.execute method, passing an array of source texts
			String[] translatedTexts = null;
			try {
				translatedTexts = Translate.execute(sourceTexts, Language.fromString(sourceCode),
						Language.fromString(targetCode));
			} catch (Exception e) {
				// TODO: decide whether to throw the Forecat exception or simply return and move to
				// the next translation service
				return;
			}

			for (int i = 0, n = sourceSegments.size(); i < n; ++i) {
				String targetText = translatedTexts[i];
				addSegments(segmentPairs, segmentCounts, targetText, Engine.BING.toString(),
						sourceSegments.get(i));
			}
		}
	}

	/*
	 * translateApertiumLocalInstallation() uses a local installation of Apertium for translating;
	 * since it uses ProcessBuilder and this class is not supported by GAE, a compiler error is
	 * obtained.
	 * 
	 * 
	 * If you just want to avoid the compiler error, go to Window/Preferences/Google/Error,warnings
	 * and in the App Engine section set to "Warning" the option "Use of non-whitelisted JRE type".
	 * 
	 * If you want to run the code from Eclipse without getting an exception, you need to go to
	 * project properties and uncheck the option for using GAE; you will also need to make a small
	 * change in the build path (by going into Properties->”Java Build Path”->”Order and Export” and
	 * then used “Up” to move the “GWT SDK” up above the “App Engine SDK”; see
	 * http://blog.elitecoderz.net/
	 * org-mortbay-thread-timeout-exception-on-new-gwt-webapplication-with
	 * -instantiations-gwt-designer-or-windowbuilder-pro/2010/05/). Remember to undo these changes
	 * if you go back to GAE (put back GWT SDK just before JRE System Library).
	 */

	protected void translateApertiumLocalInstallation(List<SourceSegment> sourceSegments,
			String sourceCode, String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) throws ForecatException {

		// TODO: check system resources and only translate if system is under a particular
		// CPU/memory load

		if (((LanguagesInput.searchEngine(languagesInput, Engine.LOCALAPERTIUM.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.LOCALAPERTIUM.toString(), sourceCode, targetCode))) {

			String delimiter = "\n\n\n";

			ProcessBuilder pb = null;
			if (localApertiumShowUnknown) {
				pb = new ProcessBuilder("apertium", "-u", sourceCode + "-" + targetCode);
			} else {
				pb = new ProcessBuilder("apertium", "", sourceCode + "-" + targetCode);
			}
			Process proc = null;
			try {
				proc = pb.start();
			} catch (IOException e) {
				return;
			}
			PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream()));
			BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

			Iterator<SourceSegment> it = sourceSegments.iterator();

			StringBuilder q = new StringBuilder();
			while (it.hasNext()) {
				SourceSegment ss = it.next();
				q.append(ss.getSourceSegmentText());
				q.append(delimiter);
			}
			out.println(q.toString());
			out.flush();
			out.close();

			StringBuilder output = new StringBuilder();
			try {
				String resultLine = in.readLine();
				while (resultLine != null) {
					output.append(resultLine + "\n");
					resultLine = in.readLine();
				}
			} catch (IOException e) {
				// TODO: decide whether to throw the Forecat exception or simply return and move
				// to the next translation service
				return;
			}

			String[] targetSegments = output.toString().split(delimiter);

			for (int i = 0, n = sourceSegments.size(); i < n; ++i) {
				String targetText = targetSegments[i];

				if (!localApertiumShowUnknown && (targetText.contains("@")
						|| targetText.contains("#") || targetText.contains("*"))) {

				} else {
					addSegments(segmentPairs, segmentCounts, targetText, Engine.APERTIUM.toString(),
							sourceSegments.get(i));
				}
			}

			proc.destroy();
		}
	}

	protected void translateCachetrans(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) throws ForecatException {

		// TODO: check system resources and only translate if system is under a particular
		// CPU/memory load

		if (((LanguagesInput.searchEngine(languagesInput, Engine.CACHETRANS.toString())) != -1)
		/*
		 * && (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
		 * Engine.CACHETRANS.toString(), sourceCode, targetCode))
		 */) {

			List<String> targetSegments = Cachetrans.getTranslation(sourceCode, targetCode,
					sourceSegments);

			for (int i = 0, n = sourceSegments.size(); i < n; ++i) {
				String targetText = targetSegments.get(i);
				addSegments(segmentPairs, segmentCounts, targetText, Engine.CACHETRANS.toString(),
						sourceSegments.get(i));
			}
		}
	}

	protected void translateDictionarium(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) throws ForecatException {

		if (((LanguagesInput.searchEngine(languagesInput, Engine.DICTIONARIUM.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.DICTIONARIUM.toString(), sourceCode, targetCode))) {

			/*
			 * InputStream file = null; InputStream dictionarium = Main.class
			 * .getResourceAsStream("/dictionarium/dictionarium.sh");
			 * 
			 * file = Main.class.getResourceAsStream( "/dictionarium/" + sourceCode + "-" +
			 * targetCode + ".dict");
			 * 
			 * FileOutputStream destination = null; try { destination = new
			 * FileOutputStream("/tmp/dictionarium.sh"); IOUtils.copy(dictionarium, destination);
			 * destination.close(); destination = new FileOutputStream("/tmp/dictionarium.data");
			 * IOUtils.copy(file, destination); destination.close(); } catch (Exception ex) {
			 * ex.printStackTrace(); return; }
			 */
			ProcessBuilder pb = null;

			pb = new ProcessBuilder("bash", dictionariumBin, dictionariumData, "1");

			Process proc = null;
			try {
				proc = pb.start();
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(-1);
			}
			PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream()));
			BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

			Iterator<SourceSegment> it = sourceSegments.iterator();
			String resultLine = "";
			SourceSegment ss;

			while (it.hasNext()) {

				ss = it.next();
				out.println(ss.getSourceSegmentText());
				// System.out.println(ss.getSourceSegmentText());
				out.flush();

				try {
					resultLine = in.readLine();
					while (resultLine != null && !resultLine.equals("")) {
						resultLine = resultLine.toLowerCase();
						// System.err.println("#D#" + ss.getSourceSegmentText() + " | " +
						// resultLine);
						addSegments(segmentPairs, segmentCounts, resultLine,
								Engine.DICTIONARIUM.toString(), ss);
						// System.err.println(resultLine);
						resultLine = in.readLine().toLowerCase();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			out.close();

			proc.destroy();
		}
	}

	private void translatePhraseum(List<SourceSegment> sourceSegments, String sourceCode,
			String targetCode, Map<String, List<SourceSegment>> segmentPairs,
			Map<String, Integer> segmentCounts, List<LanguagesInput> languagesInput,
			List<LanguagesOutput> languagesOutput) {

		if (((LanguagesInput.searchEngine(languagesInput, Engine.PHRASEUM.toString())) != -1)
				&& (LanguagesOutput.engineTranslatesLanguagePair(languagesOutput,
						Engine.PHRASEUM.toString(), sourceCode, targetCode))) {

			/*
			 * boolean direction = false; try { InputStream f = Main.class.getResourceAsStream(
			 * "/phraseum/" + sourceCode + "-" + targetCode + ".dict"); if (f != null) { direction =
			 * true; } else { f = Main.class.getResourceAsStream( "/phraseum/" + targetCode + "-" +
			 * sourceCode + ".dict"); if (f != null) { direction = false; } else { return; } } }
			 * catch (Exception ex) { System.err.println(ex.toString()); }
			 * 
			 * InputStream file = null; InputStream phraseum =
			 * Main.class.getResourceAsStream("/phraseum/phraseum.sh");
			 * 
			 * if (direction) { file = Main.class.getResourceAsStream( "/phraseum/" + sourceCode +
			 * "-" + targetCode + ".dict"); } else { file = Main.class.getResourceAsStream(
			 * "/phraseum/" + targetCode + "-" + sourceCode + ".dict"); }
			 * 
			 * FileOutputStream destination = null; try { destination = new
			 * FileOutputStream("/tmp/phraseum.sh"); IOUtils.copy(phraseum, destination);
			 * destination.close(); destination = new FileOutputStream("/tmp/phraseum.data");
			 * IOUtils.copy(file, destination); destination.close(); } catch (Exception ex) {
			 * ex.printStackTrace(); return; }
			 * 
			 */

			ProcessBuilder pb = null;

			// if (direction)
			// pb = new ProcessBuilder("bash", "/tmp/phraseum.sh", "/tmp/phraseum.data", "2",
			// "" + phraseumAlpha);
			// else
			pb = new ProcessBuilder("bash", phraseumBin, phraseumData, "1", "" + phraseumAlpha);

			Process proc = null;
			try {
				proc = pb.start();
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(-1);
			}
			PrintWriter out = new PrintWriter(new OutputStreamWriter(proc.getOutputStream()));
			BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

			Iterator<SourceSegment> it = sourceSegments.iterator();
			String resultLine = "";
			SourceSegment ss;

			while (it.hasNext()) {

				ss = it.next();
				// if (direction) {
				// out.println("^"
				// + ss.getSourceSegmentText().replace(".", "\\.").replace("*", "\\*")
				// + " |||");
				// } else {
				// out.println(" ||| "
				// + ss.getSourceSegmentText().replace(".", "\\.").replace("*", "\\*")
				// + " |||");
				// }
				out.println(ss.getSourceSegmentText());
				out.flush();

				try {
					resultLine = in.readLine();

					while (resultLine != null && !resultLine.equals("")) {
						resultLine = resultLine.trim();
						// System.err.println("#P# " + ss.getSourceSegmentText() + "|" +
						// resultLine);
						addSegments(segmentPairs, segmentCounts, resultLine,
								Engine.PHRASEUM.toString(), ss);
						resultLine = in.readLine();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			out.close();

			proc.destroy();
		}

	}
} public class Cachetrans {

	static ArrayList<Integer> segmentLengths = new ArrayList<Integer>();
	static MultiValueMap langs = null;
	static HashMap<String, HashMap<String, String>> segments = new HashMap<String, HashMap<String, String>>();
	static String configFile = "cachetrans.txt";

	public static void setConfigFile(String c) {
		configFile = c;
	}

	public static ArrayList<Integer> getSegmentLengths() {
		return segmentLengths;
	}

	public static void addSegmentLenght(int length) {
		segmentLengths.add(length);
	}

	public static MultiValueMap getLanguages() {
		if (langs == null) {
			langs = new MultiValueMap();

			langs.put("IN", "OUT");

			// if (useApertium) {
			// langs.put("en", "es");
			// langs.put("es", "en");
			// langs.put("es", "fr");
			// langs.put("fr", "es");
			// langs.put("esc", "ca");
			// langs.put("ca", "esc");
			// langs.put("eu", "es");
			// langs.put("br", "fr");
			// langs.put("cz", "en");
			// langs.put("en", "cz");
			// }
			//
			// if (useGoogle) {
			// langs.put("de", "en");
			// langs.put("en", "de");
			// langs.put("en", "es");
			// langs.put("es", "en");
			// langs.put("en", "fi");
			// langs.put("fi", "en");
			// langs.put("en", "fr");
			// langs.put("fr", "en");
			// langs.put("es", "fr");
			// langs.put("fr", "es");
			// }
		}

		return langs;
	}

	public static List<String> getTranslation(String slang, String tlang,
			List<SourceSegment> sSegments) {

		try {
			loadSegments(slang, tlang);
		} catch (IOException e) {
			System.err.println("Cant read files");
		}
		ArrayList<String> ret = new ArrayList<String>();
		HashMap<String, String> transSegments = segments.get(slang + "-" + tlang);
		String sSegment, tSegment;

		for (SourceSegment s : sSegments) {
			sSegment = s.getSourceSegmentText();// .toLowerCase();
			tSegment = transSegments.get(sSegment);
			tSegment = (tSegment != null) ? tSegment : "";
			// tSegment = tSegment.toLowerCase();
			ret.add(matchUpper(s.getSourceSegmentText(), tSegment.trim()));
			//
			// if (!tSegment.trim().equals(matchUpper(s.getSourceSegmentText(), tSegment)))
			// System.err.println(s.getSourceSegmentText() + "|" + tSegment + "|"
			// + matchUpper(s.getSourceSegmentText(), tSegment) + "|");

			// ret.add(matchUpper(s.getSourceSegmentText(), tSegment));
		}

		return ret;
	}

	public static String matchUpper(String source, String target) {
		StringBuilder sb = new StringBuilder();

		String[] sourceSplit = source.split(" ");
		String[] targetSplit = target.split(" ");

		int sourceLength = sourceSplit.length;

		String sourceWord;
		String targetWord;

		for (int i = 0; i < targetSplit.length; i++) {
			if (sb.length() > 0)
				sb.append(" ");

			if (i >= sourceLength) {
				sb.append(targetSplit[i]);
				continue;
			}
			sourceWord = sourceSplit[i];
			targetWord = targetSplit[i];

			if (Character.isUpperCase(sourceWord.charAt(0))) {
				if (sourceWord.length() > 1 && Character.isUpperCase(sourceWord.charAt(1))
						|| targetWord.length() == 0) {
					sb.append(targetWord.toUpperCase());
				} else {
					sb.append(Character.toUpperCase(targetWord.charAt(0)));
					sb.append(targetWord.substring(1));
				}
			} else {
				sb.append(targetWord);
			}
		}

		return sb.toString();
	}

	public static void loadSegments(String slang, String tlang) throws IOException {
		InputStream sSource = null, tSource = null;
		String sSeg, tSeg;
		BufferedReader sBr, tBr;
		String lang = slang + "-" + tlang;
		// String ordLang = slang.compareTo(tlang) < 0 ? slang + "-" + tlang : tlang + "-" + slang;
		HashMap<String, String> auxSegments = new HashMap<String, String>();
		if (!segments.containsKey(lang)) {

			InputStream config = UtilsConsole.openFile(configFile);
			BufferedReader configReader = new BufferedReader(
					new InputStreamReader(new DataInputStream(config)));
			String configLine;
			while ((configLine = configReader.readLine()) != null) {
				String[] files = configLine.split("\t");
				for (int i = 0; i < files.length; i += 2) {
					System.out.println(files[i] + " " + files[i + 1]);
					sSource = UtilsConsole.openFile(files[i]);
					tSource = UtilsConsole.openFile(files[i + 1]);
					sBr = new BufferedReader(new InputStreamReader(new DataInputStream(sSource)));
					tBr = new BufferedReader(new InputStreamReader(new DataInputStream(tSource)));
					while ((sSeg = sBr.readLine()) != null && (tSeg = tBr.readLine()) != null) {
						auxSegments.put(sSeg, tSeg);
					}
				}
			}

			// for (int i : segmentLengths) {
			// if (useGoogle) {
			// System.out.println("Loading Google " + i + "-segments...");
			// System.out.println("/corpus/original.subsegments/l" + i + "/" + slang + "/"
			// + slang + ".ssegs.uniq.l" + i);
			// System.out.println("/corpus/subsegment.translations/l" + i + "/" + ordLang
			// + "/google/" + slang + ".l" + i + ".clean");
			// sSource = UtilsConsole.openFile("/corpus/original.subsegments/l" + i + "/"
			// + slang + "/" + slang + ".ssegs.uniq.l" + i);
			// tSource = UtilsConsole.openFile("/corpus/subsegment.translations/l" + i + "/"
			// + ordLang + "/google/" + slang + ".l" + i + ".clean");
			// if (tSource == null) {
			// sSource.close();
			// System.out.println("ERROR");
			// break;
			// }
			//
			// sBr = new BufferedReader(new InputStreamReader(new DataInputStream(sSource)));
			// tBr = new BufferedReader(new InputStreamReader(new DataInputStream(tSource)));
			//
			// while ((sSeg = sBr.readLine()) != null && (tSeg = tBr.readLine()) != null) {
			// auxSegments.put(sSeg, tSeg);
			// }
			//
			// sBr.close();
			// tBr.close();
			//
			// }
			// if (useApertium) {
			// System.out.println("Loading Apertium " + i + "-segments...");
			// System.out.println("/corpus/original.subsegments/l" + i + "/" + slang + "/"
			// + slang + ".ssegs.uniq.l" + i);
			// System.out.println("/corpus/subsegment.translations/l" + i + "/" + ordLang
			// + "/apertium/" + slang + ".l" + i + ".clean");
			// sSource = UtilsConsole.openFile("/corpus/original.subsegments/l" + i + "/"
			// + slang + "/" + slang + ".ssegs.uniq.l" + i);
			// tSource = UtilsConsole.openFile("/corpus/subsegment.translations/l" + i + "/"
			// + ordLang + "/apertium/" + slang + ".l" + i + ".clean");
			// if (tSource == null || sSource == null) {
			// sSource.close();
			// System.out.println("ERROR");
			// System.out.println("/corpus/original.subsegments/l" + i + "/" + slang + "/"
			// + slang + ".segs.l" + i + ".low");
			// System.out.println("/corpus/subsegment.translations/l" + i + "/" + ordLang
			// + "/apertium/" + slang + ".ssegs.l" + i + ".html.clean.low");
			// break;
			// }
			// sBr = new BufferedReader(new InputStreamReader(new DataInputStream(sSource)));
			// tBr = new BufferedReader(new InputStreamReader(new DataInputStream(tSource)));
			//
			// while ((sSeg = sBr.readLine()) != null && (tSeg = tBr.readLine()) != null) {
			// auxSegments.put(sSeg, tSeg);
			// }
			// System.out.println("Loaded " + auxSegments.keySet().size() + " segments");
			//
			// sBr.close();
			// tBr.close();
			// }
			// }
			System.out.println("Segments loaded " + auxSegments.keySet().size());
			segments.put(lang, auxSegments);
		}
	}
} public class RankerComposite extends RankerShared {

	private static final long serialVersionUID = -1229745996571442964L;
	RankerShared applyBefore = null;
	RankerShared applyAfter = null;

	protected RankerComposite() {

	}

	public RankerComposite(RankerShared before, RankerShared after) {
		applyBefore = before;
		applyAfter = after;
	}

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankInp,
			List<SuggestionsOutput> input) throws ForecatException {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();

		// Only the last ranker should limit the number of suggestions to be shown
		int holdmaxSuggestions = maxSuggestions;
		maxSuggestions = Integer.MAX_VALUE;
		input = applyBefore.rankerService(rankInp, input);
		maxSuggestions = holdmaxSuggestions;
		input = applyAfter.rankerService(rankInp, input);

		for (SuggestionsOutput so : input) {
			outputSuggestionsList.add(so);
		}

		return outputSuggestionsList;
	}
} public class RankerLongestFirst extends RankerShared {

	private static final long serialVersionUID = 896290267380126773L;

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankinput,
			List<SuggestionsOutput> input) {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();
		ArrayList<Integer> sortList = new ArrayList<Integer>();
		SuggestionsOutput so;

		for (int index = 0; index < input.size(); index++) {
			sortList.add(index);
			so = input.get(index);
			so.setSuggestionFeasibility(so.getSuggestionText().length());
		}
		Quicksort q = new Quicksort();
		q.sort(sortList, input);

		for (int index = 0; index < maxSuggestions && index < input.size(); index++) {
			outputSuggestionsList.add(input.get(sortList.get(sortList.size() - index - 1)));
		}

		return outputSuggestionsList;
	}

} public class RankerLongestShortestFirst extends RankerShared {

	private static final long serialVersionUID = 2151574862257494336L;

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankInp,
			List<SuggestionsOutput> input) {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();
		ArrayList<Integer> sortList = new ArrayList<Integer>();
		SuggestionsOutput so;

		for (int index = 0; index < input.size(); index++) {
			sortList.add(index);
			so = input.get(index);
			so.setSuggestionFeasibility(so.getSuggestionText().length());
		}
		Quicksort q = new Quicksort();
		q.sort(sortList, input);

		boolean first = true;
		for (int index = 0; index < maxSuggestions && index < input.size(); index++) {
			if (first) {
				outputSuggestionsList.add(input.get(sortList.get(sortList.size() - index / 2 - 1)));
			} else {
				outputSuggestionsList.add(input.get(sortList.get(index / 2)));
			}
			first = !first;
		}

		return outputSuggestionsList;
	}
} public class RankerPosition extends RankerShared {

	private static final long serialVersionUID = 185266502718735714L;

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankInp,
			List<SuggestionsOutput> input) {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();
		ArrayList<Integer> sortList = new ArrayList<Integer>();
		SuggestionsOutput so;

		for (int index = 0; index < input.size(); index++) {
			sortList.add(index);
			so = input.get(index);
			so.setSuggestionFeasibility(Math.abs(so.getWordPosition() - rankInp.getPosition()));
		}
		Quicksort q = new Quicksort();
		q.sort(sortList, input);

		for (int index = 0; index < maxSuggestions && index < input.size(); index++) {
			outputSuggestionsList.add(input.get(sortList.get(index)));
		}

		return outputSuggestionsList;
	}
} public class RankerShortestFirst extends RankerShared {

	private static final long serialVersionUID = -8938351457344546500L;

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankInp,
			List<SuggestionsOutput> input) {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();
		ArrayList<Integer> sortList = new ArrayList<Integer>();

		SuggestionsOutput so;

		for (int index = 0; index < input.size(); index++) {
			sortList.add(index);
			so = input.get(index);
			so.setSuggestionFeasibility(so.getSuggestionText().length());
		}
		Quicksort q = new Quicksort();
		q.sort(sortList, input);

		for (int index = 0; index < maxSuggestions && index < input.size(); index++) {
			outputSuggestionsList.add(input.get(sortList.get(index)));
		}

		return outputSuggestionsList;
	}

} public class RankerShortestLongestFirst extends RankerShared {

	private static final long serialVersionUID = -5509552226829972825L;

	@Override
	public List<SuggestionsOutput> rankerService(SuggestionsInput rankInp,
			List<SuggestionsOutput> input) {
		ArrayList<SuggestionsOutput> outputSuggestionsList = new ArrayList<SuggestionsOutput>();
		ArrayList<Integer> sortList = new ArrayList<Integer>();

		SuggestionsOutput so;

		for (int index = 0; index < input.size(); index++) {
			sortList.add(index);
			so = input.get(index);
			so.setSuggestionFeasibility(so.getSuggestionText().length());
		}
		Quicksort q = new Quicksort();
		q.sort(sortList, input);

		boolean first = false;
		for (int index = 0; index < maxSuggestions && index < input.size(); index++) {
			if (first) {
				outputSuggestionsList.add(input.get(sortList.get(sortList.size() - index / 2 - 1)));
			} else {
				outputSuggestionsList.add(input.get(sortList.get(index / 2)));
			}
			first = !first;
		}

		return outputSuggestionsList;
	}
} public class SelectionNoneShared extends SelectionShared {
	/**
	 * 
	 */
	private static final long serialVersionUID = 4140355005655795685L;

	@Override
	public SelectionOutput useSegments(SelectionInput input,
			Map<String, List<SourceSegment>> segmentPairs, Map<String, Integer> segmentCounts) {
		SelectionOutput output = new SelectionOutput(segmentPairs.size());
		return output;
	}
} public class SelectionSuffixShared extends SelectionTextShared {

	/**
	 * 
	 */
	private static final long serialVersionUID = 3209760121948806078L;

	@Override
	protected boolean match(String a, String b) {

		return (UtilsShared.isSuffix(a, b));

	}

} public class SuggestionsBasic extends SuggestionsShared implements IsSerializable, Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1267521779646327709L;

	@Override
	public List<SuggestionsOutput> obtainSuggestions(SuggestionsInput input,
			Map<String, List<SourceSegment>> segmentPairs, Map<String, Integer> segmentCounts) {

		// SuggestionsOutput includes a compareTo method.
		SortedSet<SuggestionsOutput> preoutput = new TreeSet<SuggestionsOutput>();
		int closerPositionWords, closerDifference, closerPositionChars, i;

		Iterator<Entry<String, List<SourceSegment>>> it = segmentPairs.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, List<SourceSegment>> e = it.next();

			// Search for the closest source segment that could have generated this suggestion
			closerPositionWords = -1;
			closerDifference = 0;
			closerPositionChars = 0;
			String originText = "";
			String closerId = "";
			for (SourceSegment ss : segmentPairs.get(e.getKey())) {
				if (closerPositionWords == -1) {
					closerPositionWords = ss.getPosition();
					closerDifference = Math.abs(ss.getPosition() - input.getPosition());
					closerId = ss.getId() + "." + SubIdProvider.getSubId(e.getKey(), ss);
					originText = ss.getSourceSegmentText();
				} else if (Math.abs(ss.getPosition() - input.getPosition()) < closerDifference) {
					closerPositionWords = ss.getPosition();
					closerDifference = Math.abs(ss.getPosition() - input.getPosition());
					closerId = ss.getId() + "." + SubIdProvider.getSubId(e.getKey(), ss);
					originText = ss.getSourceSegmentText();
				}
			}

			i = 0;
			for (String s : input.getSourceText().split(" ")) {
				if (i == closerPositionWords)
					break;
				i++;
				closerPositionChars += s.length() + 1; // Word + a space
			}
			if (closerPositionChars > 0)
				closerPositionChars--; // Discount the last space

			if (UtilsShared.isPrefix(input.getLastWordPrefix(), e.getKey())
					&& segmentCounts.get(e.getKey()) > 0) {
				// Simple estimation of feasibility: ratio of lengths
				preoutput.add(new SuggestionsOutput(e.getKey(), originText, e.getKey().length(),
						closerId, closerPositionWords, closerPositionChars));
			}
		}

		// Return as a list.
		List<SuggestionsOutput> output = new ArrayList<SuggestionsOutput>(preoutput);

		return output;
	}

	// This code is left just to show how to use different regular expression libraries in
	// client/server sides:
	/*
	 * protected abstract boolean isPrefix(String possiblePrefix, String string);
	 */
}
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.forecat.server.translation.TranslationServerSide;
import org.forecat.server.translation.cachetrans.Cachetrans;
import org.forecat.shared.languages.LanguagesInput;
import org.forecat.shared.languages.LanguagesShared.Engine;
import org.forecat.shared.ranker.RankerComposite;
import org.forecat.shared.ranker.RankerLongestFirst;
import org.forecat.shared.ranker.RankerLongestShortestFirst;
import org.forecat.shared.ranker.RankerLongestShortestFromPosition;
import org.forecat.shared.ranker.RankerPosition;
import org.forecat.shared.ranker.RankerPressureBasic;
import org.forecat.shared.ranker.RankerPressureHeuristic;
import org.forecat.shared.ranker.RankerPressureNegativeEvidence;
import org.forecat.shared.ranker.RankerScore;
import org.forecat.shared.ranker.RankerShared;
import org.forecat.shared.ranker.RankerShortestFirst;
import org.forecat.shared.ranker.RankerShortestLongestFirst;
import org.forecat.shared.selection.SelectionContainsShared;
import org.forecat.shared.selection.SelectionEqualsShared;
import org.forecat.shared.selection.SelectionInvPrefixShared;
import org.forecat.shared.selection.SelectionNoneShared;
import org.forecat.shared.selection.SelectionPositionShared;
import org.forecat.shared.selection.SelectionPrefixShared;
import org.forecat.shared.selection.SelectionPrefixSuffixShared;
import org.forecat.shared.selection.SelectionSuffixShared;
import org.forecat.shared.suggestions.SuggestionsBasic;
import org.forecat.shared.suggestions.SuggestionsLM;
import org.forecat.shared.suggestions.SuggestionsLMBernoulli;
import org.forecat.shared.suggestions.SuggestionsLMSimpleBernoulli;
import org.forecat.shared.suggestions.SuggestionsRanker;
import org.forecat.shared.suggestions.SuggestionsSolr;
import org.forecat.shared.suggestions.SuggestionsTorchShared;
import org.forecat.shared.suggestions.LM.IRSTLMscorer;
package org.forecat.console;



public class OptionsHelper {

	/**
	 * Manages the args
	 * 
	 * @param args
	 *            Args for main
	 * @param inputLanguagesList
	 *            Possible languages
	 * @param prop
	 *            Properties from the properties file
	 */
	static void manageOptions(String[] args, List<LanguagesInput> inputLanguagesList,
			Properties prop) {
		Options opt = new Options();
		opt.addOption("h", false, "Show this help");
		opt.addOption("o", true, "Output file");
		opt.addOption("sl", true, "Segment length");
		opt.addOption("msl", true, "Minimum segment length");
		opt.addOption("l", false, "Use basic selection");
		// opt.addOption("p", false, "Use position selection");
		opt.addOption("w", false, "Use window selection");
		opt.addOption("s", true, "Source language");
		opt.addOption("t", true, "Target language");
		opt.addOption("N", true, "Size of the window");
		opt.addOption("m", true, "Maximum number of suggestions");
		opt.addOption("is", true, "Source language input file");
		opt.addOption("it", true, "Target language input file");
		opt.addOption("e", true,
				"Engines to use [A{pertium},B{ing},C{ache},D{ictionarium},P{hraseum},U{dud}] (more than one is possible)");
		opt.addOption("M", true, ".ini file for cache translator");
		opt.addOption("dictionariumbinary", true, "Location of the dictionarium binary");
		opt.addOption("dictionariumdata", true, "Location of the dictionarium data");
		opt.addOption("phraseumbinary", true, "Location of the phraseum binary");
		opt.addOption("phraseumdata", true, "Location of the phraseum data");
		opt.addOption("palpha", true, "Phraseum alpha");
		opt.addOption("S", true, "Sorting method (s|l|sl|ls|lm|sm|sc|pr|ph)");
		opt.addOption("d", true, "Deleting method (n|p|ip|ps|e)");
		opt.addOption("T", false, "Use only trusted segments");
		opt.addOption("ssp", false, "Penalty for selecting a suggestion");
		opt.addOption("c", false, "Use coverage");
		opt.addOption("z", false, "Give suggestions with nothing typed");
		opt.addOption("L", true, "Show SOLR suggestions");
		opt.addOption("noSuggestions", false, "Do not use any suggestions");
		opt.addOption("ed", false, "Use edit distance");
		opt.addOption("sed", false, "Use simple edit distance");
		opt.addOption("mi", true, "Maximum number of inserts in edit distance");
		opt.addOption("md", true, "Maximum number of deletes in edit distance");
		opt.addOption("mr", true, "Maximum number of replaces in edit distance");
		opt.addOption("med", true, "Maximum edit distance accepted for accepting a suggestion");
		opt.addOption("oec", false, "Output optimal edit cost");
		opt.addOption("lmbinary", true, "Location of the irstlm_scorer binary");
		opt.addOption("lmfile", true, "Location of the language model in plaintext");
		opt.addOption("lmvocab", true, "Location of the vocabulary for the language model");
		opt.addOption("lmTimeOut", true,
				"Timeout for the language model. Set it higher if you are using slow LM models. Probably indicates some buffering problem with the pipes.");
		opt.addOption("lines", true, "Lines to process");
		opt.addOption("allScores", false, "Output all scores");
		opt.addOption("featuresWinning", true,
				"Output features to a file in Weka arff style; winning features are classified as 1, rest 0");
		opt.addOption("featuresViable", true,
				"Output features to a file in Weka arff style; viable features are classified as 1, rest 0");
		opt.addOption("featuresTempFolder", true,
				"Temporary folder for storing the features file (2 passes are needed due some aggregate values)");
		opt.addOption("FANNstyle", false,
				"Output the features file in FANN style (else, Weka arff style is used)");
		CommandLineParser clp = new GnuParser();
		CommandLine cl = null;
		try {
			cl = clp.parse(opt, args);

			if (cl.hasOption("h")) {
				throw (new Exception("Help requested"));
			}

			if (cl.hasOption("o")) {
				Main.outFile = cl.getOptionValue("o");
			}

			if (cl.hasOption("lmbinary")) {
				IRSTLMscorer.irstlm_scorer = cl.getOptionValue("lmbinary");
			}
			if (cl.hasOption("lmfile")) {
				IRSTLMscorer.lm_location = cl.getOptionValue("lmfile");
			}
			if (cl.hasOption("lmvocab")) {
				IRSTLMscorer.vocab_location = cl.getOptionValue("lmvocab");
			}
			if (cl.hasOption("lmTimeOut")) {
				IRSTLMscorer.setTimeOut(Integer.parseInt(cl.getOptionValue("lmTimeOut")));
			}

			if (cl.hasOption("l")) {
				Main.suggestions = new SuggestionsBasic();