# Copyright 2011-2014 Splunk, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"): you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import
import csv


class DictReader(csv.DictReader, object):
    """ Splunk multi-value-aware CSV dictionary reader. """

    def __init__(self, input_file):
        super(DictReader, self).__init__(
            input_file, dialect='splunklib.searchcommands')
        self.__fieldnames = None
        self.__mv_fieldnames = None

    @csv.DictReader.fieldnames.getter
    def fieldnames(self):
        if self._fieldnames is None:
            try:
                self._fieldnames = self.reader.next()
            except StopIteration:
                self._fieldnames = []
                pass
            self.line_num = self.reader.line_num
            self.__mv_fieldnames = []
            self.__fieldnames = []
            for name in self._fieldnames:
                if name.startswith('__mv_'):
                    # Store this pair: <fieldname>, __mv_<fieldname>
                    self.__mv_fieldnames.append((name[len('__mv_'):], name))
                else:
                    self.__fieldnames.append(name)
        return self.__fieldnames

    def next(self):
        row = super(DictReader, self).next()
        self.fieldnames  # for side effects
        for fieldname, mv_fieldname in self.__mv_fieldnames:
            # Decode, store and then delete all `__mv_` fields in `row`
            list_value = DictReader._decode_list(row[mv_fieldname])
            if list_value is not None:
                row[fieldname] = list_value if len(list_value) > 1 else list[0]
            del row[mv_fieldname]
        return row

    @staticmethod
    def _decode_list(mv):
        if len(mv) == 0:
            return None
        in_value = False
        value = ''
        i = 0
        l = []
        while i < len(mv):
            if not in_value:
                if mv[i] == '$':
                    in_value = True
                elif mv[i] != ';':
                    return None
            else:
                if mv[i] == '$' and i + 1 < len(mv) and mv[i + 1] == '$':
                    value += '$'
                    i += 1
                elif mv[i] == '$':
                    in_value = False
                    l.append(value)
                    value = ''
                else:
                    value += mv[i]
            i += 1
        return l
