import inspect

import pandas as pd
import numpy as np

from util import DotDict

class DataSet(object):

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

    def initialize_expectations(self, config=None, name=None):

        if config != None:
            #!!! Should validate the incoming config with jsonschema here

            # Copy the original so that we don't overwrite it by accident
            self._expectations_config = copy.deepcopy(config)

        else:
            self._expectations_config = DotDict({
                "dataset_name" : None,
                "expectations" : []
            })

            for col in self.columns:
                self._expectations_config.expectations.append({
                    "expectation_type" : "expect_column_to_exist",
                    "kwargs" : {
                        "column" : col
                    }
                })

        self._expectations_config.dataset_name = name

    def append_expectation(self, expectation_config):
        expectation_type = expectation_config['expectation_type']

        #Drop existing expectations with the same expectation_type.
        #!!! This is good default behavior, but
        #!!!    it needs to be documented, and
        #!!!    we need to provide syntax to override it.
        self._expectations_config.expectations = filter(
            lambda exp: exp['expectation_type'] != expectation_type,
            self._expectations_config.expectations 
        )

        self._expectations_config.expectations.append(expectation_config)

    @staticmethod
    def expectation(func):

        def wrapper(self, *args, **kwargs):

            #Get the name of the method
            method_name = func.__name__

            #Fetch argument names
            method_arg_names = inspect.getargspec(func)[0][1:]

            #Construct the expectation_config object
            expectation_config = dict(
                zip(method_arg_names, args)+\
                kwargs.items()
            )

            #Add the expectation_method key
            expectation_config['expectation_type'] = method_name

            #Append the expectation to the config.
            self.append_expectation(expectation_config)

            #Finally, execute the expectation method itself
            return func(self, *args, **kwargs)

        return wrapper


    @staticmethod
    def column_expectation(func):

        def wrapper(self, column, *args, **kwargs):
            #Get the name of the method
            method_name = func.__name__

            #Fetch argument names
            method_arg_names = inspect.getargspec(func)[0][2:]

            #Construct the expectation_config object
            expectation_config = {
                "expectation_type" : method_name,
                "kwargs" : DotDict(
                    zip(method_arg_names, args)+\
                    kwargs.items()
                )
            }
            expectation_config.kwargs.column = column

            #Append the expectation to the table config.
            self.append_expectation(expectation_config)

            #Now execute the expectation method itself
            return func(self, column, *args, **kwargs)

        return wrapper

    def get_expectations_config(self):
        return self._expectations_config

    def save_expectations_config(self, filepath=None):
        if filepath==None:
            #!!! Fetch the proper filepath from the project config
            pass

        expectation_config_str = json.dumps(self.get_expectations_config, indent=2)
        file(filepath, 'w').write(expectation_config_str)

    def validate(self):
        raise NotImplementedError


@@ -1,12 +1,24 @@
+import json%0A
 import inspe
@@ -2823,18 +2823,26 @@
 onfig = 
+DotDict(
 %7B%0A
-
         
@@ -2910,20 +2910,17 @@
 args%22 : 
-DotD
+d
 ict(%0A   
@@ -3024,32 +3024,33 @@
  )%0A            %7D
+)
 %0A            exp
@@ -3068,22 +3068,28 @@
 nfig
-.
+%5B'
 kwargs
-.
+'%5D%5B'
 column
+'%5D
  = c

Fix expectation_config tests