#!/usr/bin/python
# coding: utf-8

from __future__ import unicode_literals
import json
import datetime
from unidecode import unidecode
import re
from TCL import dateutils
from itertools import ifilter

class FileParser:
    def __init__(self, filename):
        self.filename = filename
        
    def parse_json(self):
        with open(self.filename, 'r') as f:
            for line in f:
                yield json.loads(line)
                
    def request(self, **kwargs):
        return filter(lambda x: all([x.get(key) == value for (key, value) in kwargs.items()]), self.parse_json())
        

class Direction(FileParser):
    def direction(self, line_name):
        return [(d["direction_one"], d["direction_minus_one"]) for d in self.parse_json() if d["line_name"] == line_name]


class Stop(FileParser):
    def find_stop(self, query):
        decoded_query = unidecode(query).lower()
        stops = [(stop["stop_name"], unidecode(stop["stop_name"]).lower()) for stop in self.parse_json()]
        
        exact_matchs = filter(lambda stop: decoded_query in stop[1], stops)
        
        if exact_matchs:
            return list(set(zip(*exact_matchs)[0]))
            
        decoded_query = decoded_query.replace(" ", "[ -]")
            
        partial_match = filter(lambda stop: re.search(decoded_query, stop[1]) is not None, stops)
        
        return list(set(zip(*partial_match)[0]))
        
    def lines(self, **kwargs):
        return [stop["line_name"] for stop in self.request(**kwargs)]
        
            
class Schedule(FileParser):
    def __init__(self, schedule_filename, stop_filename):
        self.filename = schedule_filename
        self.stop_filename = stop_filename
        
    def next_departure(self, date, **kwargs):
        """Return the next departures."""
        
        day_before = date.replace(day=date.day-1)
        day_after = date.replace(day=date.day+1)
        
        date_type = dateutils.day_type(date)       
        day_before_type = dateutils.day_type(day_before)
        day_after_type = dateutils.day_type(day_after)
        
        schedules = []
        
        for d, day_type in ((date, date_type), (day_before, day_before_type), (day_after, day_after_type)):
            kwargs["date_type"] = day_type
            responses = self.request(**kwargs)
        
            if len(responses) > 1:
                raise ValueError("Several responses,  precise your request", responses)
                
            if len(responses) == 0:
                raise ValueError("No response for the request")
                
            response = responses[0]
                
            for hour, minutes in response["schedule"].items():
                for minute in minutes:
                    hour = int(hour)
                    minute = int(minute)
                    
                    if hour >= int(response["first_departure_hour"]):
                        schedules.append(datetime.datetime(year=d.year, month=d.month, day=d.day, hour=hour, minute=minute))
                    else:
                        schedules.append(datetime.datetime(year=d.year, month=d.month, day=d.day+1, hour=hour, minute=minute))
                    
        return sorted(filter(lambda x: date <= x, schedules))
        
    def remaining_time(self, result_number, date, **kwargs):
        yielded = 0
        for result_date in self.next_departure(date, **kwargs):
            if yielded < result_number:
                yielded += 1
                yield result_date - date
            else:
                break
        
