diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..2fe0953
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/oskdemo.jar b/demo/oskdemo.jar
new file mode 100644
index 0000000..0985e45
Binary files /dev/null and b/demo/oskdemo.jar differ
diff --git a/demo/oskdemo.txt b/demo/oskdemo.txt
new file mode 100644
index 0000000..7176bf5
--- /dev/null
+++ b/demo/oskdemo.txt
@@ -0,0 +1,5 @@
+IT Crowd
+Dune
+Game of Thrones
+Princess Bride
+Mars Attacks!
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..cb9e9ba
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+ OSK
+ OSK
+
+ UTF-8
+
+ 0.0.1-SNAPSHOT
+
+
+ junit
+ junit
+ 4.12
+
+
+
+ src
+
+
+ maven-compiler-plugin
+ 3.7.0
+
+ 1.8
+ 1.8
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/osk/OnScreenKeyboardInstructionGenerator.java b/src/main/java/osk/OnScreenKeyboardInstructionGenerator.java
new file mode 100644
index 0000000..e0fc17d
--- /dev/null
+++ b/src/main/java/osk/OnScreenKeyboardInstructionGenerator.java
@@ -0,0 +1,40 @@
+package osk;
+
+import java.util.List;
+import java.util.Scanner;
+import utils.FileParser;
+import utils.Translator;
+
+/**
+ *
+ * @author Aaron Reinard
+ *
+ * Generate OnScreen keyboard instructions for media titles in provided in flat file
+ *
+ */
+
+public class OnScreenKeyboardInstructionGenerator {
+
+ public static void main(String[] args) throws Exception {
+
+ String file = null;
+ Scanner input = new Scanner(System.in);
+
+ try {
+ System.out.print("Please enter file: ");
+ file = input.next();
+ input.close();
+
+ List titleList = FileParser.parseFlatFile(file);
+ List keyboardInstructionList = Translator.getKeyboardInstructionStringList(titleList);
+ keyboardInstructionList.forEach(x -> System.out.println(x));
+
+ } catch (Exception e) {
+ throw new Exception(
+ "Unable to translate keyboard instructions for " + file + ". " + e.getMessage());
+ }
+ }
+
+
+
+}
diff --git a/src/main/java/screen/Coordinates.java b/src/main/java/screen/Coordinates.java
new file mode 100644
index 0000000..234a64d
--- /dev/null
+++ b/src/main/java/screen/Coordinates.java
@@ -0,0 +1,37 @@
+package screen;
+
+/**
+ *
+ * @author Aaron Reinard
+ *
+ * Contains coordinates used for keyboard navigation instructions
+ *
+ */
+public class Coordinates {
+
+ private int x;
+ private int y;
+
+ public Coordinates(int x, int y) {
+ this.x = x;
+ this.y = y;
+
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public void setX(int value) {
+ this.x = value;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public void setY(int value) {
+ this.y = value;
+ }
+
+}
diff --git a/src/main/java/screen/Key.java b/src/main/java/screen/Key.java
new file mode 100644
index 0000000..63619f5
--- /dev/null
+++ b/src/main/java/screen/Key.java
@@ -0,0 +1,34 @@
+package screen;
+
+/**
+ *
+ * @author Aaron Reinard
+ *
+ */
+public class Key {
+
+ private String value;
+ private Coordinates coordinates;
+
+ public Key(String character, Coordinates values) {
+ setValue(character);
+ setCoordinates(values);
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public Coordinates getCoordinates() {
+ return coordinates;
+ }
+
+ public void setCoordinates(Coordinates values) {
+ this.coordinates = values;
+ }
+
+}
diff --git a/src/main/java/screen/Keyboard.java b/src/main/java/screen/Keyboard.java
new file mode 100644
index 0000000..3151271
--- /dev/null
+++ b/src/main/java/screen/Keyboard.java
@@ -0,0 +1,62 @@
+package screen;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Aaron Reinard
+ *
+ * Keyboard dictionary containing keyset and coordinates
+ *
+ */
+
+public class Keyboard {
+
+ private List keys = null;
+
+ public Keyboard() {
+ this.keys = setKeys();
+ }
+
+ public List getKeys() {
+ return keys;
+ }
+
+ public Key getKey(String value) {
+ Key result = null;
+ for (Key keyMap : getKeys()) {
+ if (keyMap.getValue().equalsIgnoreCase(value)) {
+ result = keyMap;
+ break;
+ }
+ }
+ return result;
+ }
+
+
+ private List setKeys() {
+
+ List keyList = new ArrayList();
+ List lines = new ArrayList();
+
+ lines.add("ABCDEF");
+ lines.add("GHIJKL");
+ lines.add("MNOPQR");
+ lines.add("STUVWX");
+ lines.add("YZ1234");
+ lines.add("567890");
+
+ int yInt = 0;
+ for (String line : lines) {
+ for (int xInt = 0; xInt < line.length(); xInt++) {
+ String value = String.valueOf(line.charAt(xInt));
+ Coordinates coordinates = new Coordinates(xInt, yInt);
+ keyList.add(new Key(value, coordinates));
+ }
+ yInt++;
+ }
+ return keyList;
+ }
+
+}
diff --git a/src/main/java/utils/FileParser.java b/src/main/java/utils/FileParser.java
new file mode 100644
index 0000000..5c22b4e
--- /dev/null
+++ b/src/main/java/utils/FileParser.java
@@ -0,0 +1,43 @@
+package utils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class FileParser {
+
+ /**
+ *
+ * @param filePath inputFile
+ * @return list of strings parsed from flat file
+ * @throws IOException
+ */
+ public static List parseFlatFile(String filePath) throws IOException {
+ List resultList = new ArrayList();
+ try {
+ File input = new File(filePath);
+ InputStream inputStream = new FileInputStream(input);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ resultList = reader.lines().map(mapToString).collect(Collectors.toList());
+ reader.close();
+ } catch (Exception e) {
+ throw new IOException("unable to parse file " + filePath + "; " + e.getMessage());
+ }
+ return resultList;
+ }
+
+ private static Function mapToString = (line) -> {
+ String items[] = line.split("\\r?\\n");
+ String item = items[0];
+ return item;
+
+ };
+
+}
diff --git a/src/main/java/utils/Translator.java b/src/main/java/utils/Translator.java
new file mode 100644
index 0000000..a0eaa5f
--- /dev/null
+++ b/src/main/java/utils/Translator.java
@@ -0,0 +1,185 @@
+package utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import screen.Coordinates;
+import screen.Keyboard;
+
+/**
+ *
+ * @author Aaron Reinard
+ *
+ * Used to convert strings and lists of string into on screen keyboard instructions.
+ * */
+
+public class Translator {
+
+ private static Keyboard keyboard = new Keyboard();
+
+ /**
+ * @return returns list of character string instructions for keyboard
+ * @throws Exception
+ */
+ public static List getKeyboardInstructionStringList(List titles)
+ throws Exception {
+ List navigationList = new ArrayList();
+ for (String title : titles) {
+ navigationList.add(getKeyboardInstructionString(title));
+ }
+ return navigationList;
+ }
+
+ /**
+ *
+ * @param title media title to be formatted into keyboard character instructions
+ * @return formatted keyboard character instructions
+ * @throws Exception
+ */
+ public static String getKeyboardInstructionString(String title) throws Exception {
+
+ // remove unsupported special characters
+ title = getFormattedTitle(title);
+
+ String result = "";
+ String startValue = "A";
+ String endValue = "";
+
+ try {
+ for (int i = 0; i < title.length(); i++) {
+ endValue = String.valueOf(title.charAt(i));
+ result += getSingleCharacterKeybordInstructions(startValue, endValue) + ",";
+ if (!endValue.equals(" ")) {
+ startValue = endValue;
+ } else {
+ endValue = startValue;
+ }
+ }
+ } catch (Exception e) {
+ throw new Exception("Unable to parse title " + e.getMessage());
+
+ }
+ return result.substring(0, result.length() - 1);
+ }
+
+ /**
+ * creates a set of keyboard charater instructions to navigate between two keys
+ *
+ * @param startValue starting character
+ * @param endValue
+ * @return keyboard instructions to navigate between characters
+ * @throws Exception
+ */
+ public static String getSingleCharacterKeybordInstructions(String startValue, String endValue)
+ throws Exception {
+
+ String result = null;
+
+ // if space, don't calculate coordinateDiff, just use 'S'
+ if (endValue.equals(" ")) {
+ result = "S";
+ } else {
+ Coordinates startCoordinates = keyboard.getKey(startValue).getCoordinates();
+ Coordinates endCoordinates = keyboard.getKey(endValue).getCoordinates();
+ Coordinates coordinateDiff = getCoordinateDiff(startCoordinates, endCoordinates);
+
+ String yNavigationString = getSingleCharacterYKeyboardInstructions(coordinateDiff.getY());
+ String xNavigationString = getSingleCharacterXKeyboardInstructions(coordinateDiff.getX());
+ result = yNavigationString + xNavigationString + "#";
+ }
+ return result;
+
+ }
+
+ /**
+ * creates a horizontal set of keyboard instructions based on integer
+ *
+ * @param diff number of character movements required
+ * @return a horizontal set of keyboard instructions based on integer
+ *
+ */
+ private static String getSingleCharacterXKeyboardInstructions(int diff) {
+
+ String result = "";
+
+ for (int i = 0; i < Math.abs(diff); i++) {
+ result += getKeyboardInstructionCharacter(diff, "X");
+ }
+
+ return result;
+
+ }
+
+ /**
+ * creates a vertical set of keyboard instructions based on integer
+ *
+ * @param diff number of character movements required
+ * @return a horizontal set of keyboard instructions based on integer
+ *
+ */
+ private static String getSingleCharacterYKeyboardInstructions(int diff) {
+
+ String result = "";
+
+ for (int i = 0; i < Math.abs(diff); i++) {
+ result += getKeyboardInstructionCharacter(diff, "Y");
+ }
+
+ return result;
+
+ }
+
+ /**
+ *
+ * @param direction of navigation
+ * @param coordinateType X or Y axis
+ * @return character value required for keyboard instructions
+ */
+ private static String getKeyboardInstructionCharacter(int diff, String coordinateType) {
+
+ String plusValue = null;
+ String minusValue = null;
+
+ if (coordinateType.equalsIgnoreCase("X")) {
+ plusValue = "L,";
+ minusValue = "R,";
+ } else {
+ plusValue = "U,";
+ minusValue = "D,";
+ }
+
+ if (diff == 0) {
+ return "";
+ } else if (diff < 0) {
+ return minusValue;
+ } else {
+ return plusValue;
+ }
+
+ }
+
+ /**
+ *
+ * @param title
+ * @return title with replaced non-alpha numeric characters
+ */
+ public static String getFormattedTitle(String title) {
+ String result = title.replaceAll("[^A-Za-z0-9 ]", "");
+ return result;
+ }
+
+ /**
+ *
+ * @param startCoordinates starting key
+ * @param endCoordinates ending key
+ * @return difference in keyboard coordinates between two keys
+ */
+ private static Coordinates getCoordinateDiff(Coordinates startCoordinates,
+ Coordinates endCoordinates) {
+ int xDiff = startCoordinates.getX() - endCoordinates.getX();
+ int yDiff = startCoordinates.getY() - endCoordinates.getY();
+ return new Coordinates(xDiff, yDiff);
+ }
+
+
+
+}
diff --git a/src/test/java/utilstest/TestRunner.java b/src/test/java/utilstest/TestRunner.java
new file mode 100644
index 0000000..bcd519d
--- /dev/null
+++ b/src/test/java/utilstest/TestRunner.java
@@ -0,0 +1,14 @@
+package utilstest;
+
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+
+public class TestRunner {
+ public static void main(String[] args) {
+ System.out.println("Executing tests...");
+ Result result = JUnitCore.runClasses(TranslatorTest.class);
+ result.getFailures().forEach(x -> System.out.println(x));
+ System.out.println("Test execution complete!");
+ }
+
+}
diff --git a/src/test/java/utilstest/TranslatorTest.java b/src/test/java/utilstest/TranslatorTest.java
new file mode 100644
index 0000000..5652725
--- /dev/null
+++ b/src/test/java/utilstest/TranslatorTest.java
@@ -0,0 +1,74 @@
+package utilstest;
+
+import static org.junit.Assert.assertEquals;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import utils.Translator;
+
+public class TranslatorTest {
+
+ OutputStream stream;
+
+
+ @Before
+ public void initialize() {
+ try {
+ stream = new FileOutputStream("");
+ } catch (FileNotFoundException e) {
+ }
+ }
+
+ @After
+ public void cleanup() {
+ try {
+ if (stream != null)
+ stream.close();
+ } catch (Exception e) {
+
+ }
+ }
+
+ @Test
+ public void test_translator_getKeyboardInstructionStringBaseline() {
+
+ String translated = null;
+ try {
+ translated = Translator.getKeyboardInstructionString("IT Crowd");
+ } catch (Exception e) {
+ }
+
+ String expected = "D,R,R,#,D,D,L,#,S,U,U,U,R,#,D,D,R,R,R,#,L,L,L,#,D,R,R,#,U,U,U,L,#";
+ assertEquals(expected, translated);
+ }
+
+ @Test
+ public void test_translator_verifySpecialCharacterHandle() {
+
+ String formatted = Translator.getFormattedTitle("~!@#$%1^&*()A<>?:2{}}|+");
+ assertEquals("1A2", formatted);
+
+ }
+
+ @Test
+ public void test_translator_getSingleCharacterKeyboardInstructions() {
+
+ String actual = null;
+ try {
+ actual = Translator.getSingleCharacterKeybordInstructions("A", "A");
+ } catch (Exception e) {
+ }
+ assertEquals("#",actual);
+
+ try {
+ actual = Translator.getSingleCharacterKeybordInstructions("M", "A");
+ } catch (Exception e) {
+ }
+ assertEquals("U,U,#",actual);
+
+ }
+
+}