import os
import sys

json_folder = os.path.expanduser("~") + "/.todopy/"
import json

class NoSuchListError(Exception): pass

class TodoList:
    """
    Contains the code needed to manage the todo list.
    """
    def __init__(self, json_location):
        """
        Sets up the list.
        """
        self.json_location = json_location
        self.load()

    def add(self, name, deadline, description):
        """
        Adds an item to the list
        """
        try:
            last_id = self.list[-1].id
        except IndexError:
            # No items in list
            last_id = - 1

        new_item = TodoItem(last_id + 1, name, deadline, description)
        self.list.append(new_item)
        return new_item

    def __str__(self):
        stringlist = []

        for item in self.list:
            stringlist.append(str(item.id) + '\t' + str(item.name) + '\t' + str(item.deadline) + '\t' + str(item.description))

        string = '\n'.join(stringlist)
        return string

    def idLessString(self):
        """
        Returns a string of this list without the id numbers.
        """
        string = ''
        for item in self.list:
            string = string + str(item.name) + '\t' + str(item.deadline) + '\t' + str(item.description) + '\n'
        string = string[:-1] # Cut out final newline
        return string

    def __len__(self):
        return len(self.list)

    def __iter__(self):
        return self.forward()

    def __getitem__(self, item_id):
        print(item_id)
        for todo in self.list:
            if todo.id == item_id:
                return todo
            else:
                print(item_id, 'not matched for', todo.id, todo)
        raise IndexError('No such item')

    def forward(self):
        current_item = 0
        while (current_item < len(self)):
            item = self.list[current_item]
            current_item += 1
            yield item

    def __contains__(self, item):
        if item in self.list:
            return True
        return False

    def remove(self, item_id):
        """
        Removes an item from the list.
        """
        todo = self[item_id]
        removed_text = todo.name
        self.list.remove(todo)
        return removed_text

    def load(self):
        """
        Loads the list data from file.
        """
        try:
            json_file = open(self.json_location, 'r')
            json_text = json_file.read()
            json_file.close()

            json_list = json.loads(json_text)

            self.list = []
            for item in json_list:
                self.list.append(TodoItem(item['id'], item['name'], item['deadline'], item['description']))
                print(item)

        except IOError:
            raise NoSuchListError

    def save(self):
        """
        Writes the list data to file.
        """
        json_file = open(self.json_location, 'w')

        json_list = []
        # Re-order indices
        id = 0
        for item in self.list:
            item.id = id
            json_list.append(item.asdict())
            id += 1

        json_file.write(json.dumps(json_list))
        json_file.close()

class TodoItem:
    def __init__(self, id, name, deadline, description):
        self.id = id
        self.name = name
        self.deadline = deadline
        self.description = description

    def __str__(self):
        return self.name

    def asdict(self):
        return {'id': self.id, 'name': self.name, 'deadline' : self.deadline, 'description' : self.description }

class Todo:
    """
    Allows a user to edit their todo list.
    """

    def run(self):
        """
        Runs the function with the same name as sys.argv[1]
        """
        try:
            func = getattr(self, sys.argv[1])
        # Command not found
        except AttributeError:
            print("The command", sys.argv[1], "doesn't exist")
        # No action defined, show help
        except IndexError:
            self.help()
        else:
            if callable(func):
                try:
                    func()
                except IndexError:
                    print("Missing argument for command '" + sys.argv[1] + "' check help")
                except NoSuchListError:
                    print("That list does not exist. Please try another list," \
                          + " or create the list using create <list>")

    def install(self):
        """
        Sets up the data files for storing the todo list.
        """
        try:
            os.mkdir(json_folder)
        except OSError as e:

            if e.errno == 17:
                # Folder exists, do nothing
                pass
            else:
                # Something has gone seriously wrong - rethrow the exception
                raise e

        self.create("todo", False)

        print("Simple Python Todo Installed")

    def create(self, name=None, print_output=True):
        """
        Creates a new list.
        """
        if name is None:
            list_name = sys.argv[2]
        else:
            list_name = name

        try:
            json_file = open(self.getListFilename(list_name), "r")
            json.loads(json_file.read())
            if print_output:
                print(list_name, "already exists.")
        except IOError as e:
            if e.errno == 2: # No file, create file.
                json_file = open(self.getListFilename(list_name), "w")
                json_file.write("[]")
                if print_output:
                    print("Created:", list_name)


    def delete(self):
        """
        Deletes a list.
        """

        list_name = sys.argv[2]
        os.remove(self.getListFilename(list_name))

        print(list_name, "removed")

    def add(self):
        """
        Adds an item to the todo list.
        """
        text = ' '.join(sys.argv[2:])
        self.addto("todo", text)

    def addto(self, list_name="", text=""):
        """
        Adds an item to the specified list.
        """
        if list_name == "":
            list_name = sys.argv[2]
            text = ' '.join(sys.argv[3:])

        todo_list = TodoList(self.getListFilename(list_name))
        todo_list.add(text)
        todo_list.save()

        print("Added to:", list_name)
        print("Added:", text)

    def done(self):
        """
        Removes an item from the todo list by ID
        """
        item_id = int(sys.argv[2])
        self.donein("todo", item_id)

    def donein(self, list_name="todo", item_id=None):
        """
        Removes an item from a certain list.
        """
        if item_id is None:
            list_name = sys.argv[2]
            item_id = int(sys.argv[3])


        todo_list = TodoList(self.getListFilename(list_name))
        removed_text = todo_list.remove(item_id)
        todo_list.save()

        print("Removed from:", list_name)
        print("Removed:", removed_text)

    def list(self, list_name="todo"):
        """
        Prints out a todo list. If a list name is specified, prints that list,
        otherwise prints out the default, "todo" list.
        """
        if len(sys.argv) > 2:
            list_name = sys.argv[2]

        print(TodoList(self.getListFilename(list_name)))

    def getListFilename(self, list_name):
        """
        Gets the Filename for a list.
        """
        filename = json_folder + list_name.lower() + ".json"
        return filename

    def move(self, item_id=None, lname_from=None, lname_to=None):
        """
        Move list item another list.
        """

        item_id = int(sys.argv[2])
        lname_from = sys.argv[3]
        lname_to = sys.argv[4]

        list_from = TodoList(self.getListFilename(lname_from))
        list_to = TodoList(self.getListFilename(lname_to))

        list_to.add(list_from[item_id].text)
        list_from.remove(item_id)

        list_from.save()
        list_to.save()

        print("Moved to: %s" % lname_to)

    def help(self):
        """
        Prints out help information
        """
        print
        print("Usage (simple):")
        print("\t add <message> \t- Adds a message to the todo list")
        print("\t list \t\t- Lists all current todo items")
        print("\t done <ID> \t\t- Removes a finished todo item with the specified ID")
        print("\t install \t- Sets up the data files needed to run the script")
        print("\n")
        print("Usage (multiple lists):")
        print("\t addto <list> <message> \t - Adds a message to a certain list")
        print("\t list <list> \t\t\t - Prints out a certain list.")
        print("\t donein <list> <ID> \t\t - Marks a message done in a certain list")
        print("\t create <list> \t\t\t - Creates a list with the name <list>")
        print("\t delete <list> \t\t\t - Deletes the list with the name <list>")
        print("\t move <ID> <from> <to> \t\t - Move list item another list")
        print("\n")

Todo().run()