# OPERATION SourceFromCSV
# PYTHON_SYNTAX
# # Sourcing from a CSV without included headers:
#   app.source_from_csv("test.csv", headers=["name","email"])
#
# # Sourcing from a CSV with included headers:
#   app.source_from_csv("test.csv")
#
#
# PYTHON_NOTES
#
# The **headers** field is an array of header names(in order) for which to construct the tuples generated by the CSV.
#
##  PYTHON_EXAMPLE
# # Source from the "test.csv" file
# source = app.source("test.csv", headers=["name", "email"])
#
#
# class MyEach:
#   # use the tuples emitted from the CSV
#   def execute(self, controller, tup):
#     name = tup["name"]
#     email = tup["email"]
#
# stream = source.each(MyEach)
#
import traceback
from counter import Counter
from controller import Controller, ParentDeadException, UserEndCycleException
from helper import Helper
import csv

class SourceFromCSV:
  def __init__(self, app):
    self._app = app



  def begin_cycle(self, controller):
    self._file = file(self._filename)
    self._csv = csv.reader(self._file)
    if (self._headers is None):
      self._headers = self._csv.next()


  def next_tuple(self, controller):

    try:
      tup = {}
      csv_line = self._csv.next()

      i = 0
      for header in self._headers:
        tup[header] = csv_line[i]
        i += 1

      controller.emit(tup)
    except StopIteration:
      pass


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

    self._name = kwargs.pop('name', None)
    if self._name == None:
      self._name = "source_"+Counter.get()

    self._type = "source"
    self._end_cycle_policy = "null_emit"

    emits = kwargs.pop('emits', None)
    if emits == None:
      emits = ["stream_"+Counter.get()]
    elif isinstance(emits, basestring):
      emits = [emits]
    self._emits = emits


    if len(args) >= 1:

      # source from relation
      if isinstance(args[0], basestring):
        self._filename = args[0]
        Helper.check_file(self._filename)

    self._headers = kwargs.get("headers", None)

    # check the operation
    Helper.check_name("source", self._name, self._app._names)
    Helper.check_emits("source", self._emits, self._app._streams)

  def run_operation(self):

    controller = Controller(self._emits, self._app._options)
    controller.get_pidDir()

    while True:
      try:
        d = controller.read()
        if d == None:
          continue
        elif "command" not in d:
          controller.log("Not a command")
        elif d["command"] == "prepare":
          pass
        elif d["command"] == "begin_cycle":
            self.begin_cycle(controller)
        elif d["command"] == "next":
            self.next_tuple(controller)
        elif d["command"] == "ack":
          controller.ack(d.get("id",None))
        elif d["command"] == "fail":
          controller.fail(d.get("id",None))
        else:
          controller.log("Invalid command")
      except UserEndCycleException, e:
        pass
      except KeyboardInterrupt:
        raise
      except ParentDeadException, e:
        controller.log("jvm appears to have died")
        raise
      except:
        controller.fail("Exception in source: "+traceback.format_exc())
      controller.done()
