import numpy as np
import pandas as pd
import savReaderWriter as sr

from collections import defaultdict
from quantipy.core.tools.dp.prep import start_meta, condense_dichotomous_set
import os

def parse_sav_file(filename, path=None, name="", ioLocale="en_US.UTF-8", ioUtf8=True, dichot=None,
                   dates_as_strings=False, text_key="main"):
    """ Parses a .sav file and returns a touple of Data and Meta

        Parameters
        ----------
        filename : str, name of sav file
            path : str, the path to the sav file
            name : str, a name for the sav (stored in the meta)
        ioLocale : str, the locale that SavReaderWriter uses
          ioUtf8 : bool, Boolean that indicates the mode in which text
                         communicated to or from the I/O Module will be.
          dichot : dicit, default=None
                   The values to use for True/False in dichotomous sets
dates_as_strings : bool, default=False
                   If True then all dates from the input SAV will be treated as
                   Quantipy strings.
        text_key : str, default="main"
                   The text_key that all labels should be stored under.

        Returns
        -------
        (data, meta) : The data is a Pandas Dataframe
                     : The meta is a JSON dictionary
    """
    filepath="{}{}".format(path or '', filename)
    filepath = os.path.abspath(filepath).decode('cp1252')
    data = extract_sav_data(filepath, ioLocale=ioLocale, ioUtf8=ioUtf8)
    meta, data = extract_sav_meta(filepath, name="", data=data, ioLocale=ioLocale,
                                  ioUtf8=ioUtf8, dichot=dichot, dates_as_strings=dates_as_strings,
                                  text_key=text_key)
    return (meta, data)

def extract_sav_data(sav_file, ioLocale='en_US.UTF-8', ioUtf8=True):
    """ see parse_sav_file doc """
    with sr.SavReader(sav_file, returnHeader=True, ioLocale=ioLocale, ioUtf8=ioUtf8) as reader:
        header = next(reader)
        dataframe = pd.DataFrame.from_records((x for x in reader), coerce_float=False)
        dataframe.columns = header
        for column in header:
            if isinstance(dataframe[column].dtype, np.object):
                # Replace None with NaN because SRW returns None if casting dates fails (dates are of type np.object))
                values = dataframe[column].dropna().values
                if len(values) > 0:
                    if isinstance(values[0], unicode):
                        dataframe[column] = dataframe[column].dropna().map(unicode.strip)
                    elif isinstance(values[0], str):
                        # savReaderWriter casts dates to str
                        dataframe[column] = dataframe[column].dropna().map(str.strip)
                        # creating DATETIME objects should happen here
        return dataframe

def extract_sav_meta(sav_file, name="", data=None, ioLocale='en_US.UTF-8',
                     ioUtf8=True, dichot=None, dates_as_strings=False,
                     text_key="main"):

    if dichot is None: dichot = {'yes': 1, 'no': 0}

    """ see parse_sav_file doc """
    with sr.SavHeaderReader(sav_file, ioLocale=ioLocale, ioUtf8=ioUtf8) as header:
        # Metadata Attributes
        # ['valueLabels', 'varTypes', 'varSets', 'varAttributes', 'varRoles',
        #  'measureLevels', 'caseWeightVar', 'varNames', 'varLabels', 'formats',
        #  'multRespDefs', 'columnWidths', 'fileAttributes', 'alignments',
        #  'fileLabel', 'missingValues']
        metadata = header.dataDictionary(True)

    meta = start_meta(text_key=text_key)
    meta['info']['text'] = 'Converted from SAV file {}.'.format(name)
    meta['info']['from_source'] = {'pandas_reader':'sav'}