class GraphReader {

    protected TaskGraphVO createGraphFromScriptOutput(String output) {

        String[] lines = output.split("\\n");
        if (lines.length == 0) {
            return new TaskGraphVO(new TaskNode(new PipelineTask()));
        }
        // first line is always name of the root task
        String mainTaskName = lines[0].trim();
        // important: for main task inputs and outputs are reverted, due
        // to luigi's approach to graph calculation
        TaskNode mainTask = new TaskNode(new PipelineTask(mainTaskName));
        TaskNode currentTask = mainTask;

        Map<String, TaskNode> tasks = new HashMap<>();
        tasks.put(mainTaskName, mainTask);
        mainTask.getTask().setId(1L);

        for (int i = 1; i < lines.length; i++) {
            String line = lines[i];
            if (line.isEmpty()) {
                continue;
            }
            if (line.startsWith(INPUT_START) && currentTask != null) {
                String value = line.substring(INPUT_START.length());
                parseValue(currentTask.getInputs(), value);
            } else if (line.startsWith(OUTPUT_START) && currentTask != null) {
                String value = line.substring(OUTPUT_START.length());
                parseValue(currentTask.getOutputs(), value);
            } else if (line.startsWith(TOOL_START) && currentTask != null) {
                parseTool(currentTask, line);
            } else if (line.contains(DEPENDENCY_DELIMITER)){
                String[] dependency = line.split(DEPENDENCY_DELIMITER);
                TaskNode fromTask = getOrCreateNode(dependency[0].trim(), tasks);
                String secondTaskName = dependency.length > 1 ? dependency[1].trim(): "";
                // for helper tasks (input files) we omit name and add their output as
                // input to all pipeline
                if (dependency.length == 1 || secondTaskName.isEmpty()) {
                    currentTask = null;
                    mainTask.getOutputs().addAll(fromTask.getInputs());
                } else {
                    TaskNode toTask = getOrCreateNode(secondTaskName, tasks);
                    currentTask = toTask;
                    toTask.addParent(fromTask.getTask().getId());
                }
            }
        }
        //switch output and input for main task
        mainTask.switchInputOutput();
        TaskGraphVO graph = new TaskGraphVO(mainTask);
        graph.setTasks(new ArrayList<>(tasks.values()));
        return graph;
    }

}