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

import unittest
import os
from pprint import pprint
import sys

import xio


class TestCases(unittest.TestCase):

    def test_base(self):

        root = xio.resource()
        test1 = root.put('test1', 'OK1')
        test2 = root.put('test2', 'OK2')
        test21 = test2.put('test21', 'OK21')
        test3 = root.put('test3', lambda req: 'OK3')

        assert root.get('test1').content == 'OK1'
        assert root.get('test2').content == 'OK2'
        assert root.get('test2').get('test21').content == 'OK21'

        # check resources are the sames when using handler (prevent children lost, etc)
        assert test1 == root.get('test1') == root.get('test1')
        # warning each resource may difer in handler case
        #assert test3 == root.get('test3') == root.get('test3')

        root = xio.resource()
        root.put('www', lambda req: 'OK' if req.GET else req.PASS)
        root.put('www/page1', 'PAGE1')
        assert root.get('www').content == 'OK'
        assert root.get('www/page1').content == 'PAGE1'

    def test_base_handler(self):

        root = xio.resource()
        root.put('www', lambda req: req._debug())

        root = xio.resource(lambda req: req._debug())
        assert root.get().content

    def test_base_client(self):
        root = xio.resource(lambda req: fail() if not req.GET else 'ok')

        assert root.get().status == 200
        assert root.post().status == 500

        cli = xio.resource(root)
        assert cli.get().status == 200
        assert cli.post().status == 500

    def test_chain_without_handler(self):
        # gestion chain

        root = xio.resource()
        c = root.put('a/b/c', 'OKc')
        d = c.put('d', 'OKd')
        e = root.put('a/b/e', 'OKe')
        h = root.get('a/b/c').put('f/g/h', 'OKh')
        k = root.get('a/b/c').put('i/j/k', 'OKk')
        #h = root.put('a/b/c').put('l/m/n','OKn')

        assert root.get('a/b/c/d').content == 'OKd'
        assert root.get('a/b').get('c').get('i').get('j/k') == root.get('a/b/c/i/j/k')
        assert root.get('a/b/c/i/j/k')

    def test_chain_with_handler(self):
        # gestion chain et handler

        root = xio.resource()
        root.put('www', lambda req: "OK %s %s" % (req.method, req.path))

        www = root.get('www')
        # assert callable( www.content ) # fail !
        assert www.get('').content == 'OK GET '
        assert www.put('mydata').content == 'OK PUT mydata'
        assert www.post('').content == 'OK POST '
        assert root.get('www/a').content == 'OK GET a'
        assert root.get('www/a/b').content == 'OK GET a/b'
        assert root.get('www/a/b/c').content == 'OK GET a/b/c'

        assert root.get('www/a/b/c').content == root.get('www').get('a').get('b').get('c').content == 'OK GET a/b/c'
        assert root.get('www').get('a').get('b').get('c').content == 'OK GET a/b/c'
        assert root.get('www/a').get('b/c').content == root.get('www/a/b').get('c').content == root.get('www').get('a/b/c').content == 'OK GET a/b/c'

    def test_404(self):
        root = xio.resource()
        res1 = root.put('test1', 'OK1')
        res2 = root.put('test2/test3', 'OK2')
        assert root.get('test1') == res1
        assert root.get('test2').get('test3') == res2

        # __nonzero__ compare le contenu de la resource
        assert root.get('a').status == 404
        #assert not root.get('a')
        #assert not root.get('a').get('a')
        #assert root.get('a').get('a') != None

        assert root.get('test1').content == 'OK1'

        # same result using client
        cli = xio.resource(root)
        assert cli.get('a').status == 404

    def test_500(self):
        root = xio.resource()
        root.put('test1', lambda req: fail() if req.query else None)

        # direct request
        assert root.get('test1').status == 200
        assert root.get('test1', {'key': 'val'}).status == 500

        # same result using client
        cli = xio.resource(root)
        assert root.get('test1', {'key': 'val'}).status == 500

    def test_routes(self):

        root = xio.resource()
        root.put(':a', 'a')
        root.put(':a/:b', 'a/b')
        root.put(':a/:b/:c', 'a/b/c')

        assert root.get('1').content == 'a'
        assert root.get('1/2').content == 'a/b'
        assert root.get('1/2/3').content == 'a/b/c'

        root = xio.resource()
        root.put(':a', lambda req: 'a' if req.GET else req.PASS)
        root.put(':a/:b', lambda req: 'a/b' if req.GET else req.PASS)
        root.put(':a/:b/:c', lambda req: 'a/b/c' if req.GET else req.PASS)

        assert root.get('1', {}).content == 'a'
        assert root.get('1/2', {}).content == 'a/b'
        assert root.get('1/2/3', {}).content == 'a/b/c'

    def test_routes_handler(self):

        root = xio.resource()
        root.bind('a', lambda req: 'a handler')
        root.bind('a/:b', lambda req: 'b handler')
        root.bind('a/:b/:c', lambda req: 'c handler')

        assert root.get('a').content == 'a handler'
        assert root.get('a/b').content == 'b handler'
        assert root.get('a/b/c').content == 'c handler'

        assert root.post('a').content == 'a handler'
        assert root.post('a/b').content == 'b handler'
        assert root.post('a/b/c').content == 'c handler'

        assert root.put('a').content == 'a handler'
        assert root.put('a/b').content == 'b handler'
        assert root.put('a/b/c').content == 'c handler'

    def test_routes_params(self):

        root = xio.resource()
        root.put('www/:container', lambda req: req.context if req.GET else req.PASS)
        root.put('www/:container/:item', lambda req: req.context)

        c = root.get('www/:container')
        c1 = root.get('www/container1')
        c2 = root.get('www/container2')
        assert c1._handler == c1._handler == c._handler

        data = root.get('www/container1/1234', {'var1': 'ok'}).content
        assert data[':container'] == 'container1'
        assert data[':item'] == '1234'

    def test_about_inline(self):

        root = xio.resource()

        @root.bind('test1')
        def _(req):
            """
            options: GET,POST
            input:
                params:
                    - name: param1
                    - name: param2
            """
            if req.GET or req.POST:
                return 'ok1'

        @root.bind('test2')
        def _(req):
            """
            options: MYCUSTOMMETHOD
            input:
                params:
                    - name: myparam
            """
            if req.MYCUSTOMMETHOD:
                return 'ok2'

        @root.bind('test3')
        def _(req):
            """
            options: GET,POST
            description: 2x multiplication
            input:
                params:
                    -   name: param1
                        required: true
            tests:
                -   method: GET
                    input:
                        param1: 12
                    assert:
                        content: 24
                -   method: POST
                    input:
                        param1: 25
                    assert:
                        content: 25

            """
            return 2 * int(req.input.get('param1'))

        about = root.about('test1').content
        assert about != 'ok1'
        assert 'POST' in about['options']
        assert 'param2' in str(about['methods']['POST']['input']['params'])

        about = root.about('test2').content
        assert 'MYCUSTOMMETHOD' in about['options']
        #assert 'myparam' in str(about['methods']['MYCUSTOMMETHOD']['input']['params'])
        assert root.get('test2').mycustommethod('myvalue').content == 'ok2'

        testresult = root.get('test3', {'param1': 300})
        assert testresult.status == 200
        assert testresult.content == 600

    def test_xmethod(self):

        root = xio.resource()

        @root.bind('www')
        def _(req):
            """
            options: CUSTOMMETHOD1, CUSTOMMETHOD2
            """
            return 'OK %s %s' % (req.method, req.xmethod)

        www = root.get('www')
        # declared methods
        assert www.customMethod1().content == 'OK POST CUSTOMMETHOD1'
        assert www.customMethod2().content == 'OK POST CUSTOMMETHOD2'
        # undeclared methods
        assert www.customMethod3().status == 405  # method not allowed

    def test_handler_checkpoint(self):

        root = xio.resource()

        @root.bind('www')
        def _(req):
            """
            options: GET, POST
            input:
                params:
                    -   name: param1
                        required: true
                    -   name: param2
                        required: true
                        type: integer
                    -   name: param3
                        type: float
                    -   name: param4
                        pattern: 'OK(.*)OK'
            """
            return 'TESTOK'

        www = root.get('www')

        # declared methods
        assert www.get().status == 400                                              # missing args param1
        assert www.get({'param1': 'value1'}).status == 400                           # missing args param2
        assert www.get({'param1': 'value1', 'param2': 'value2'}).status == 400         # param2 must be integer
        assert www.get({'param1': 'value1', 'param2': 123}).status == 200              # ok
        assert www.get({'param1': 'value1', 'param2': 123, 'param3': 'value2'}).status == 400        # param3 must be float
        assert www.get({'param1': 'value1', 'param2': 123, 'param3': 5.5}).status == 200             # ok
        assert www.get({'param1': 'value1', 'param2': 123, 'param4': 'test'}).status == 400         # pattern not match
        assert www.get({'param1': 'value1', 'param2': 123, 'param4': 'OKtestOK'}).status == 200     # ok
        assert www.delete().status == 405   # method not allowed

    def test_prevent_path_modifications(self):
        """
        check that any path update by handlers won't impact parent resource path
        handlers need to use req.redirect for any path redirection for requestt handling
        """

        root = xio.resource()

        @root.bind('test')
        def _(req):
            req.path = 'some updated path by handler'
            return 'ok'

        test1 = root.get('test')
        test2 = test1.get()

        assert test1.content == test2.content == 'ok'
        assert test1.path == test2.path == 'test'

    def test_api(self):
        return self.skipTest('tofix')

        root = xio.resource()

        @root.bind('www/test1')
        def _(req):
            """
            options: GET,POST
            input:
                params:
                    - name: param1
                    - name: param2
            """
            if req.GET or req.POST:
                return 'ok1'

        @root.bind('www/test2')
        def _(req):
            """
            options: MYCUSTOMMETHOD
            input:
                params:
                    - name: myparam
            """
            if req.MYCUSTOMMETHOD:
                return 'ok2'

        about = root.about().content
        assert about.get('resources', {}).get('www') != None

        about = root.get('www').about().content

        assert 'test1' in about.get('resources')
        assert 'test2' in about.get('resources')

        api = root.api().content
        assert api

    def test_handler_instance(self):
        instance = xio.app()
        cli = xio.resource(instance)
        assert cli.about().content['id'] == instance.id

    def test_handler_http(self):
        cli = xio.resource('http://127.0.0.1')

    def _test_handler_namespace(self):
        xio.handlers.bind('myns', lambda req: 'namespace %s ok' % req.path)
        cli = xio.resource('myns:somepath')
        assert cli.get('subpath').content == 'namespace somepath/subpath ok'
        assert cli.get().content == 'namespace somepath ok'  # tofix namespace somepath/ ok

    def _test_handler_xrn(self):
        root = xio.resource('xrn:test')
        assert root._handler

    def test_handler_directory(self):
        # file://host/path or file:///path
        directory = os.path.dirname(os.path.realpath(__file__))
        client = xio.resource('file://' + directory)
        assert client._handler

        resp = client.get()
        assert resp.status == 200
        assert resp.content

    def test_handler_file(self):

        filepath = os.path.realpath(__file__)
        client = xio.resource('file://' + filepath)

        resp = client.get()
        assert resp.status == 200
        assert resp.content

    def test_handler_http(self):

        root = xio.resource('http://127.0.0.1')
        assert root._handler

        root = xio.resource('https://127.0.0.1/subpath')
        assert root._handler

        """
        client = xio.resource('http://127.0.0.1')

        resp = client.get('/')


        assert resp.status == 200

        root = client.head()
        assert root.status == 200
        assert not root.content
        """
        """
        lib = root.get('lib')
        assert lib.status == 200
        assert lib.content
        """

    def test_handler_callable(self):
        root = xio.resource(lambda req: req.path)
        assert root._handler

    def test_handler_resource(self):
        app = xio.app()
        root = xio.resource(app)
        assert root._handler


if __name__ == '__main__':

    unittest.main()
