#!/usr/bin/env python3
#
# Copyright (C) 2016-2017 ShadowMan
#
import os
import json
import time
import flask
import logging
import asyncio
import aiohttp
from collections import namedtuple
from functools import partial

from aiohttp import web
from trainquery import train_station, utils, train_query, train_query_result, exceptions

async_loop = asyncio.get_event_loop()
train_station.init(async_loop)

with open('templates/index.html') as html:
    response_text = html.read()

async def index_handler(request):
    return web.Response(text = response_text, content_type = 'text/html', charset = 'utf-8')

WS_Response_Data = namedtuple('WS_Response_Data', 'event data')

def _server_emit(ws, ws_response):
    if ws_response is None:
        raise RuntimeWarning('the event handler must be return a response')
    if isinstance(ws_response, WS_Response_Data):
        if isinstance(ws_response.data, dict):
            response_event = ws_response.event
            ws_response = ws_response.data
            ws_response.update({'event': response_event})
    if isinstance(ws_response, dict):
        ws.send_json(ws_response)
    if isinstance(ws_response, str):
        ws.send_str(ws_response)

def check_train_station(request, emit):
    if (train_station.get(request.get('station_name'))):
        emit(WS_Response_Data(
            # event
            'response.train.station',
            # data
            {
                'status': True, 'message': 'success',
                'key': request.get('key'),
                'station_code': train_station.get(request.get('station_name'))
            }
        ))
    else:
        emit(WS_Response_Data(
            # event
            'response.train.station',
            # data
            {
                'status': False, 'message': 'the station not found',
                'key': request.get('key'),
                'station_code': None
            }
        ))

async def foreach_train(result, emit):
    if isinstance(result, train_query_result.ResultParser):
        # emit response.train.count
        emit(WS_Response_Data(
            # event
            'response.train.count',
            # data
            {
                'status': True,
                'message': 'succeed',
                'count': len(result.get_trains_code())
            }
        ))
        # emit response.train.list
        emit(WS_Response_Data(
            # event
            'response.train.list',
            # data
            {
                'status': True,
                'message': 'succeed',
                'list': result.get_trains_code()
            }
        ))
        # all train information
        for train_code in result.get_trains_code():
            selector = result.select(train_code)

            emit(WS_Response_Data(
                # event
                'response.train.profile',
                # data
                {
                    'train_code': selector.train_code,
                    'start_time': selector.start_time,
                    'arrive_time': selector.arrive_time,
                    'total_time': selector.total_time,
                    'start_station': selector.start_station,
                    'end_station': selector.end_station,
                    'available': selector.purchase_flag
                }
            ))
            # try:
            #     print('\t', selector.train_code, await selector.seat())
            # except exceptions.ReTryExceed as e:
            #     logging.info('query seat retry count exceeded. ignore this train[{}]'.format(selector.train_code))
            # print('\t\t', selector.train_code, await selector.check())

async def query_train_list(request, emit):
    emit(WS_Response_Data(
        # event
        'response.train.query.progress',
        # data
        {
            'status': True,
            'progress': 0,
            'message': 'start'
        }
    ))

    try:
        from_station = request.get('from')
        to_station = request.get('to')
        train_date = request.get('date')
        ts = request.get('ts')
        train_ts = time.mktime(time.strptime(train_date, '%Y-%m-%d'))
        await train_query.TrainQuery().query(
            from_station, to_station,