# Author: Dennis Lutter <lad1337@gmail.com>
# Author: Jonathon Saine <thezoggy@gmail.com>
# URL: http://code.google.com/p/sickbeard/
#
# This file is part of SickRage.
#
# SickRage is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickRage is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickRage.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import with_statement

import os
import time
import urllib
import datetime
import re
import traceback

import sickbeard
from sickrage.helper.common import dateFormat, dateTimeFormat, timeFormat
from sickrage.helper.encoding import ek
from sickrage.helper.exceptions import CantUpdateShowException, ex, ShowDirectoryNotFoundException
from sickrage.helper.quality import get_quality_string
from sickrage.media.ShowFanArt import ShowFanArt
from sickrage.media.ShowNetworkLogo import ShowNetworkLogo
from sickrage.media.ShowPoster import ShowPoster
from sickrage.media.ShowBanner import ShowBanner
from sickrage.show.ComingEpisodes import ComingEpisodes
from sickrage.show.History import History
from sickrage.show.Show import Show
from sickrage.system.Restart import Restart
from sickrage.system.Shutdown import Shutdown

from versionChecker import CheckVersion
from sickbeard import db, logger, ui, helpers
from sickbeard import search_queue
from sickbeard import image_cache
from sickbeard import classes
from sickbeard import processTV
from sickbeard import network_timezones, sbdatetime
from sickbeard.common import DOWNLOADED
from sickbeard.common import FAILED
from sickbeard.common import IGNORED
from sickbeard.common import Overview
from sickbeard.common import Quality
from sickbeard.common import SKIPPED
from sickbeard.common import SNATCHED
from sickbeard.common import SNATCHED_PROPER
from sickbeard.common import UNAIRED
from sickbeard.common import UNKNOWN
from sickbeard.common import WANTED
from sickbeard.common import statusStrings
import codecs

try:
    import json
except ImportError:
    import simplejson as json


from tornado.web import RequestHandler

indexer_ids = ["indexerid", "tvdbid"]

RESULT_SUCCESS = 10  # only use inside the run methods
RESULT_FAILURE = 20  # only use inside the run methods
RESULT_TIMEOUT = 30  # not used yet :(
RESULT_ERROR = 40  # only use outside of the run methods !
RESULT_FATAL = 50  # only use in Api.default() ! this is the "we encountered an internal error" error
RESULT_DENIED = 60  # only use in Api.default() ! this is the access denied error
result_type_map = {
    RESULT_SUCCESS: "success",
    RESULT_FAILURE: "failure",
    RESULT_TIMEOUT: "timeout",
    RESULT_ERROR: "error",
    RESULT_FATAL: "fatal",
    RESULT_DENIED: "denied",
}
# basically everything except RESULT_SUCCESS / success is bad


class ApiHandler(RequestHandler):
    """ api class that returns json results """
    version = 5  # use an int since float-point is unpredictable

    def __init__(self, *args, **kwargs):
        super(ApiHandler, self).__init__(*args, **kwargs)

    #def set_default_headers(self):
        #self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')

    def get(self, *args, **kwargs):
        kwargs = self.request.arguments
        for arg, value in kwargs.iteritems():
            if len(value) == 1:
                kwargs[arg] = value[0]

        args = args[1:]

        # set the output callback
        # default json
        outputCallbackDict = {
            'default': self._out_as_json,
            'image': self._out_as_image,
        }

        accessMsg = u"API :: " + self.request.remote_ip + " - gave correct API KEY. ACCESS GRANTED"
        logger.log(accessMsg, logger.DEBUG)

        # set the original call_dispatcher as the local _call_dispatcher
        _call_dispatcher = self.call_dispatcher
        # if profile was set wrap "_call_dispatcher" in the profile function
        if 'profile' in kwargs:
            from profilehooks import profile

            _call_dispatcher = profile(_call_dispatcher, immediate=True)
            del kwargs["profile"]

        # if debug was set call the "_call_dispatcher"
        if 'debug' in kwargs:
            outDict = _call_dispatch
er(args, kwargs)  # this way we can debug the cherry.py traceback in the browser
            del kwargs["debug"]
        else:  # if debug was not set we wrap the "call_dispatcher" in a try block to assure a json output
            try:
       
         outDict = _call_dispatcher(args, kwargs)
            except Exception, e:  # real internal error oohhh nooo :(
                logger.log(u"API :: " + ex(e), logger.ERROR)
                errorData = {"error_msg": ex(e),
                             "args": args,
                             "kwargs": kwargs}
                outDict = _responds(RESULT_FATAL, errorData,
                                    "SickRage encountered an internal error! Please report to the Devs")

        if 'outputType' in outDict:
            outputCallback = outputCallbackDict[outDict['outputType']]
        else:
            outputCallback = outputCallbackDict['default']

        try:self.finish(outputCallback(outDict))
        except:pass

    def _out_as_image(self, dict):
        self.set_header('Content-Type', dict['image'].get_media_type())
        return dict['image'].get_media()

    def _out_as_json(self, dict):
        self.set_header("Content-Type", "application/json;charset=UTF-8")
        try:
            out = json.dumps(dict, ensure_ascii=False, sort_keys=True)
            callback = self.get_query_argument('callback', None) or self.get_query_argument('jsonp', None)
            if callback is not None:
                out = callback + '(' + out + ');'  # wrap with JSONP call if requested
        except Exception, e:  # if we fail to generate the output fake an error
            logger.log(u"API :: " + traceback.format_exc(), logger.DEBUG)
            out = '{"result": "%s", "message": "error while composing output: %s"}' %\
                  (result_type_map[RESULT_ERROR], ex(e))
        return out

    def call_dispatcher(self, args, kwargs):
        """ calls the appropriate CMD class
            looks for a cmd in args and kwargs
            or calls the TVDBShorthandWrapper when the first args element is a number
            or returns an error that there is no such cmd
        """
        logger.log(u"API :: all args: '" + str(args) + "'", logger.DEBUG)
        logger.log(u"API :: all kwargs: '" + str(kwargs) + "'", logger.DEBUG)

        cmds = None
        if args:
            cmds = args[0]
            args = args[1:]

        if "cmd" in kwargs:
            cmds = kwargs["cmd"]
            del kwargs["cmd"]

        outDict = {}
        if cmds is not None:
            cmds = cmds.split("|")
            multiCmds = bool(len(cmds) > 1)
            for cmd in cmds:
                curArgs, curKwargs = self.filter_params(cmd, args, kwargs)
                cmdIndex = None
                if len(cmd.split("_")) > 1:  # was a index used for this cmd ?
                    cmd, cmdIndex = cmd.split("_")  # this gives us the clear cmd and the index

                logger.log(u"API :: " + cmd + ": curKwargs " + str(curKwargs), logger.DEBUG)
                if not (multiCmds and cmd in ('show.getbanner', 'show.getfanart', 'show.getnetworklogo', 'show.getposter')):  # skip these cmd while chaining
                    try:
                        if cmd in _functionMaper:
                            # map function
                            func = _functionMaper.get(cmd)

                            # add request handler to function
                            func.rh = self

                            # call function and get response back
                            c