r"""CountVectorTransformer uses
    sklearn.feature_extraction.text.CountVectorizer to generate count
    vector features (Bag of Words, n-grams, ...).

:Author:
    Matthias Manhertz
:Copyright:
    (c) Matthias Manhertz 2015
:Licence:
    MIT
"""

from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer
from .feature_transformer import FeatureTransformer
from .combine_tweets import combine_tweets
from itertools import izip
from time import time


class CountVectorTransformer(FeatureTransformer):
    r"""Transforms json files into count vector features

        The CountVectorTransformer makes it easy to transform .json
        files containing twitter-data (like the ones generated by
        twistml's filtering and / or preprocessing steps) into count
        vector features (e.g. bag of words or n-grams).

        <Notes>

        References
        ----------
        For possible arguments to CountVectorizer see scikit-learn_.

        .. _scikit-learn: http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html

        Example Usage
        -------------
        ::
            import twistml as tml

            filepaths = tml.find_files('c:/data/')
            cvg = tml.features.CountVectorTransformer(min_df=2,
                                                      analyzer='word')
            features = cvg.transform(filepaths)

    """  # NOQA

    def __init__(self, use_tfidf=True, **kwargs):
        r"""Initialize the CountVectorTransformer

        Optional keyword arguments for twistml.features.combine_tweets
        and sklearn.feature_extraction.text.CountVectorizer can be
        given and will be passed along.

        Parameters
        ----------
        use_tfidf : bool, optional
            Whether TFIDF transformation should be applied to the count
            vectors. (Default is True)

        References
        ----------
        For possible arguments to CountVectorizer see scikit-learn_.

        For possible arguments to combine_tweets see its documentation.

        .. _scikit-learn: http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html

        """  # NOQA

        # extract the arguments that are meant for CountVectorizer()
        cvargs = {key: value for key, value in kwargs.iteritems()
                  if key in CountVectorizer.__init__.func_code.co_varnames}
        # extract the arguments that are meant for combine_tweets()
        self.tweetargs = {key: value for key, value in kwargs.iteritems()
                          if key in combine_tweets.func_code.co_varnames}
        self.vectorizer = CountVectorizer(**cvargs)

        self.tfidf = use_tfidf
        # sanity check
        d = {key: value for key, value in kwargs.iteritems()
             if key not in CountVectorizer.__init__.func_code.co_varnames and
                key not in combine_tweets.func_code.co_varnames}  # NOQA
        if d:
            raise ValueError('unknown keyword arg(s): {}'.format(d.keys))
        pass

    def transform(self, filepaths):
        r"""Transforms twitter data in files into a dict mapping
            datestamps to count vectors.

            The tweets contained in the files specified in `filepaths`
            are combined (their content for each date is concatenated)
            and the resulting concatenated texts are turned into one
            count vector per day.

            Parameters
            ----------
            filepaths : list(str)
                A list of files that contain tweets in the typical
                format (dict[str, str]) as generated by the filtering
                and / or preprocessing functions in twistml.

            Returns
            -------
            daily_counts : dict[datetime, csr-matrix]
                A dict mapping datestamps to count vectors in
                scipy.sparse.csr_matrix format.

        """

        combined = combine_tweets(filepaths, **self.tweetargs)
        datestamps, tweets = combined.keys(), combined.values()
        del(combined)

        t0 = time()
        print "Vectorizing...",
        counts = self.vectorizer.fit_transform(tweets)
        if self.tfidf:
            tfidf = TfidfTransformer()
            counts = tfidf.fit_transform(counts)
        print " done in  {0:.1f}min.".format((time()-t0)/60)

        return dict(izip(datestamps, counts))

    pass
