from __future__ import unicode_literals

import abc
import copy
import logging

from jsonpointer import resolve_pointer, JsonPointerException

logger = logging.getLogger(__name__)


class BaseTransformer(object):

    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def _transform_string(self, string, doc):
        raise NotImplementedError

    @abc.abstractproperty
    def schema(self):
        raise NotImplementedError

    def transform(self, doc):
        return self._transform(self.schema, doc)

    def _transform(self, schema, doc):
        transformed = {}
        for key, value in schema.items():
            if isinstance(value, dict):
                transformed[key] = self._transform(value, doc)
            elif isinstance(value, list):
                transformed[key] = self._transform_list(value, doc)
            elif isinstance(value, tuple) and len(value) == 2 and isinstance(value[0], tuple):
                transformed[key] = self._transform_args_kwargs(value, doc)
            elif isinstance(value, tuple):
                transformed[key] = self._transform_tuple(value, doc)
            elif isinstance(value, basestring):
                transformed[key] = self._transform_string(value, doc)
            elif callable(value):
                transformed[key] = value(doc)
        return transformed

    def _transform_list(self, l, doc):
        return [
            self._transform(item, doc) for item in l
        ]

    def _transform_tuple(self, l, doc):

        fn, values = l[-1], l[:-1]
        args = []

        for value in values:
            if isinstance(value, basestring):
                args.append(self._transform_string(value, doc))
            elif callable(value):
                args.append(value(doc))
        return fn(*args)

    def _transform_args_kwargs(self, l, doc):
        fn = l[1]
        return fn(
            *self._transform_args(l[0], doc),
            **self._transform_kwargs(l[0], doc)
        )

    def _transform_args(self, t, doc):
        return [self._transform_string(arg, doc) for arg in t[0]]

    def _transform_kwargs(self, t, doc):
        return {
            k: self._transform_string(v, doc) for k, v in t[1].items()
        } if len(t) == 2 else {}


class XMLTransformer(BaseTransformer):

    __metaclass__ = abc.ABCMeta

    def _transform_string(self, string, doc):
        return doc.xpath(string, namespaces=self.namespaces)

    @abc.abstractproperty
    def namespaces(self):
        raise NotImplementedError


class JSONTransformer(BaseTransformer):

    __metaclass__ = abc.ABCMeta

    def _transform_string(self, val, doc):
        try:
            return resolve_pointer(doc, val)
        except JsonPointerException:
            return ''

@@ -622,36 +622,63 @@
             
-if isinstanc
+transformed%5Bkey%5D = self._transform_valu
 e(value, dic
@@ -679,13 +679,11 @@
 e, d
-ict):
+oc)
 %0A   
@@ -691,34 +691,126 @@
     
-        transformed%5Bkey%5D =
+return transformed%0A%0A    def _transform_value(self, value, doc):%0A        if isinstance(value, dict):%0A            return
  sel
@@ -826,36 +826,32 @@
 orm(value, doc)%0A
-    
         elif isi
@@ -884,38 +884,22 @@
         
-    transformed%5Bkey%5D =
+return
  self._t
@@ -916,36 +916,32 @@
 ist(value, doc)%0A
-    
         elif isi
@@ -1027,38 +1027,22 @@
         
-    transformed%5Bkey%5D =
+return
  self._t
@@ -1074,36 +1074,32 @@
 e, doc)%0A        
- 
-   
 elif isinstance(
@@ -1125,38 +1125,22 @@
         
-    transformed%5Bkey%5D =
+return
  self._t
@@ -1170,28 +1170,24 @@
 oc)%0A        
-   
- 
 elif isinsta
@@ -1222,38 +1222,22 @@
         
-    transformed%5Bkey%5D =
+return
  self._t
@@ -1264,36 +1264,32 @@
 e, doc)%0A        
-    
 elif callable(va
@@ -1310,68 +1310,25 @@
     
-    transformed%5Bkey%5D = value(doc)%0A        return transformed
+return value(doc)
 %0A%0A  
@@ -1408,16 +1408,22 @@
 ransform
+_value
 (item, d

Add transform value to deal with lists