#!/usr/bin/python
"""parse.py parses the given testdata.txt file and produces:
    1) A list of all organs with a "central" attribute
    2) A dictionary of key-value pairs of all the "things in my head"
    3) An ordered (by alpha) sort of all items at the upper level

Copyright 2015 Dean Stevens

Licensed under the MIT License (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://opensource.org/licenses/MIT

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

__author__ = "Dean Stevens"
__status__ = "Prototype"
__version__ = "0.1.0"

import argparse
import ast
import json


def get_data_dict(data_path):
    """Opens the data file, reads all of the lines, discards the lines outside
    the dictionary structure then parses the remaining information into
    a dictionary that can be used for the rest of the evaluation
    Args:
        data_path - str representing the pathname to the data file to be
                    processed
    Returns:
        A Python collection dictionary containing the parsed data
    """
    print("\nUsing data file at: '{0}'\n".format(data_path))

    with open(path, "r") as f:
        all_lines = f.read().splitlines()

    # We don't want to accumulate lines that are outside the outer {} of the
    # dictionary, which we assume will both be in the first position on the
    # start / end lines, so we use this flag to tell us when to accumulate
    # lines.
    accum = False
    nl = []
    for i in all_lines:
        if i[0] == '{':
            accum = True
        elif i[0] == '}':
            # We need the closing brace, then we'll stop accumulating
            nl.append(i)
            accum = False

        if accum:
            nl.append(i)

    dict_str = ''.join(nl)
    # Convert the str representation of the dictionary into a proper Python
    # collection object
    dd = ast.literal_eval(dict_str)

    return dd


def central_organs(data_dict):
    """Generates a list of organs with a "central" attribute
    """
    print("\n\nList of organs with \"central\" attribute:\n")

    organs = data_dict['organs']

    def has_central(organ):
        # Checks to see if the specified organ has the "central" attribute.
        # Returns True if the attribute is present for the organ
        return True if "central" in organ.values() else False

    def get_central_key(organ):
        # Searches the items in the organ dictionary for a value that
        # specifies the "central" attribute.
        # Returns the key for that value, None if it isn't found
        retval = None
        for k,v in organ.items():
            if v == "central":
                retval = k
                break

        return retval
        
    central_o = [get_central_key(o) for o in organs if has_central(o)]
    # Note: Used json.dumps() to get the " shown in the instructions instead
    #       of the normal ' generated by print.
    print(json.dumps(central_o))


def in_my_head(data_dict):
    """Generates a dictionary of key-value pairs of all the "things in my 
    head"
    """
    print("\n\nDictionary of key-value pairs of all the "
          "\"things in my head\":\n")
    # Note: Did not reproduce the smart quotes close (0x94 ?) shown on
    #       line 14 of the instructions.
    # Note: Used json.dumps() to get the " shown in the instructions instead
    #       of the normal ' generated by print.
    print(json.dumps(data_dict['things in my head']))


def sorted_top_level(data_dict):
    """Generates an ordered (by alpha) sort of all items at the upper level
    """
    print("\n\nAn ordered (by alpha) sort of all items at the upper level:\n")
    # Note: The output shown on line 19 of the instructions is:
    #       "container": "container key says "hi"
    #       Instead, our output is:
    #       "container":"container key says 'hi'"
    # Note: Used json.dumps() to get the " shown in the instructions instead
    #       of the normal ' generated by print.
    for k in sorted(data_dict.keys()):
        print("\"{0}\":{1}".format( k, json.dumps(data_dict[k])))


if __name__ == '__main__':

    # argparse lets us provide both a default value and help text
    default_path = "./testdata.txt"

    help_str = ("Pathname to the test data file, if absent "
                "will use default test data file '{0}'").format(default_path)
    parser = argparse.ArgumentParser(
                      description=__doc__
                     ,formatter_class=argparse.RawDescriptionHelpFormatter
                     )
    parser.add_argument("data_file_path"
                        ,nargs='?'
                        ,default=default_path
                        ,help=help_str
                        )

    path = parser.parse_args().data_file_path

    dd = get_data_dict(path)

    central_organs(dd)
    in_my_head(dd)
    sorted_top_level(dd)

    print("\nDONE!\n")

