def __init__(self):
     self.mp = Mixpanel(api_key=ENV["mp"]["api_key"], api_secret=ENV["mp"]["api_secret"])
class MPService():
    def __init__(self):
        self.mp = Mixpanel(api_key=ENV["mp"]["api_key"], api_secret=ENV["mp"]["api_secret"])
      
    #
    # get list of most common events over the past 31 days
    #
    def get_event_list(self):
        return self.mp.request(['events', 'names'], {'type': 'general', 'limit':5})

    #
    # get Events data
    #
    def get_events_data(self, events, start_date, end_date, unit, event_type, viz="line"):
        interval = (end_date - start_date).days
        today_date = datetime.utcnow()
        # mix panel always returns events data using end_data as today's date
        # diff between the end date requested by app and today's date
        diff = (today_date - end_date).days
        if diff > 0:
          interval = (today_date - start_date).days
        
        interval = self.get_interval(unit, interval)
        
        # call api
        response_data = self.mp.request(['events'], { 
            'event' : events, 'unit' : unit, 
            'interval' : interval, 'type': event_type
        })

        # bit of massaging is needed here to remove extra data
        dates = []

        if diff > 0:  # chop values of
          diff = self.get_interval(unit, diff)
          #dates = response_data["data"]["series"][:-(diff-1)] # remove last n elements
          dates = response_data["data"]["series"][-(diff):] # keep firt elements

        events_data = []
        for event_name in events:
          event_data = response_data["data"]["values"][event_name]
          for d in dates:
            del event_data[d]
          
          # convert date string to time in epoch
          if viz == "line":
            new_event_data = {}
            for event_date, count in event_data.iteritems():
                event_date = (calendar.timegm((datetime.strptime(event_date, '%Y-%m-%d')).timetuple())) * 1000
                new_event_data[event_date] = count
            events_data.append({"name": event_name, "data": sorted(new_event_data.iteritems(), key=lambda x: x[0])})            
          else:
            events_data.append({"name": event_name, "data": sorted(event_data.iteritems(), key=lambda x: x[0])})            
        return events_data

    #
    # Given unit and interval in days, get new value of interval
    #
    def get_interval(self, unit, interval):
      if unit == "hour":
          interval = interval * 24
      elif unit == "week":
          interval = interval // 7 
      elif unit == "month":
          interval = interval // 30
      return interval

    #
    # get list of funnels
    #
    def get_funnel_list(self):
      return self.mp.request(['funnels/list'], {})
       

    #
    # make api call to get funnel data
    #
    def get_funnel(self, funnel_id, start_date, end_date, group_by="", where_cond=""):
      return self.mp.request(['funnels'], {
        'funnel_id': funnel_id, 'from_date': start_date, 
          'to_date':end_date, 'on': group_by, 'where':where_cond})

    #
    # get funnel  data
    #
    def get_funnel_data(self, funnel_id, start_date, end_date, viz="bar"):
      # get funnel data
      funnel_data = self.get_funnel(funnel_id, start_date, end_date)
      
      # construct an empty funnel object
      funnel = {'funnel_id': funnel_id, 'from_date': start_date, 'to_date':end_date,
                   'data': []}

      if viz == "bar":
        funnel["data"] = self.transform_funnel_data(funnel_data)                
      else:
        funnel["data"] = self.transform_funnel_data(funnel_data, True)
      return funnel

    #
    # get funnel breakdown data
    #
    def get_funnel_breakdown_data(self, funnel_id, start_date, end_date, viz="bar"):
      # get funnel data
      funnel_data = self.get_funnel(funnel_id, start_date, end_date)
      
      # construct an empty funnel object
      funnel = {'funnel_id': funnel_id, 'from_date': start_date, 'to_date':end_date,
                   'data': []}
      if viz == "bar":
        funnel["data"] = self.transform_funnel_breakdown_data(funnel_data)                
      else:
        funnel["data"] = self.transform_funnel_breakdown_data(funnel_data, True)                
      return funnel    

    #
    # get funnel data
    #
    def get_filtered_funnel_data(self, funnel_id, start_date, end_date, group_by="", where_cond="", viz="bar"):
      # get funnel data
      funnel_data = self.get_funnel(funnel_id, start_date, end_date, group_by, where_cond)

      # construct an empty funnel object
      funnel = {'funnel_id': funnel_id, 'from_date': start_date, 'to_date':end_date,
                   'data': []}

      funnel["data"] = self.transform_filtered_funnel_data(funnel_data)
      return funnel

    #
    # get funnel conversion rate
    #
    def get_funnel_conversion_rate_data(self, funnel_id, start_date, end_date, viz="bar"):
      # construct an empty funnel object
      funnel = {'funnel_id': funnel_id, 'from_date': start_date, 'to_date':end_date,
                   'data': []}
      # get funnel data
      funnel_data = self.get_funnel(funnel_id, start_date, end_date)
      
      conversion_data = {}
      for event_date, values in sorted(funnel_data["data"].iteritems(), key=lambda x: x[0]):
        event_date = (calendar.timegm((datetime.strptime(event_date, '%Y-%m-%d')).timetuple())) * 1000
        ana =  values["analysis"]
        if int(ana["starting_amount"]) != 0:
          conversion_data[event_date] = round(int(ana["completion"])/int(ana["starting_amount"]), 3)
        else:
          conversion_data[event_date] = 0
      funnel["data"] = [{"name": "Conversion Rate", "data": sorted(conversion_data.iteritems(), key=lambda x: x[0])}]
      return funnel

    #
    # transform funnel data
    #
    def transform_funnel_data(self, funnel_data, table_view=False):
        # reduce all steps related to funnels grouped by date in one list
        funnel_step_count_by_day = [step for info in funnel_data["data"].values() for step in info["steps"]]
        # now aggregate the list of dictionaries 
        funnel_steps = defaultdict(int)
        for steps in funnel_step_count_by_day:
          funnel_steps[steps['event']] += steps['count']
        
        if not table_view:
          data = defaultdict(list)        
          for category,value in sorted(funnel_steps.iteritems(), key=lambda x: x[1], reverse=True):
            data["categories"].append(category)
            data["series"].append(value)
          return data
        else: # transform data to table
          data = []
          row = OrderedDict()
          row["Funnel"] = "Overall" 
          prev_step_val = None
          for category,value in sorted(funnel_steps.iteritems(), key=lambda x: x[1], reverse=True):
            if prev_step_val is None:
              prev_step_val = value
            row[category] = "%d (%.2f%%)" % (value, (100 * float(value)/float(prev_step_val)))
            prev_step_val = value
          data.append(row)
          return data

         

    #
    # transform funnel breakdown data by step by date
    #
    def transform_funnel_breakdown_data(self, funnel_data, table_view=False):
      #print funnel_data
      #by_step_by_date = defaultdict(list)
      by_step_by_date = OrderedDict()
      categories = []
      for event_date, values in sorted(funnel_data["data"].iteritems(), key=lambda x: x[0]):
        event_date = datetime.strptime(event_date, '%Y-%m-%d').strftime('%b %d')
        #(calendar.timegm((datetime.strptime(event_date, '%Y-%m-%d')).timetuple())) * 1000
        categories.append(event_date)
        for step in values["steps"]:
            series_name = step["event"]
            count = step["count"]
            if series_name in by_step_by_date:
              #by_step_by_date[series_name].append([event_date, count])
              by_step_by_date[series_name].append(count)
            else:
              #by_step_by_date[series_name] = [[event_date, count]]
              by_step_by_date[series_name] = [count] 
        data = {"categories": categories, "series": by_step_by_date}
      if not table_view:
        return data
      else:
        grid_data = []
        for key, value in data["series"].iteritems():
            l = zip(data["categories"], value) # zip date and event count together 
            l.insert(0, ("Event", key))
            grid_row = OrderedDict(l)
            grid_data.append(grid_row)
        return grid_data
        #events_data.append({"name": event_name, "data": sorted(event_data.iteritems(), key=lambda x: x[0])})            

        

    #
    # transform fitler data
    #
    def transform_filtered_funnel_data(self, funnel_data):
        # first bring all events for a property value under one list
        by_prop = defaultdict(list)
        for info in funnel_data["data"].values():
            for prop, items in info.iteritems():
                by_prop[prop].extend(items)

        # now aggregate by property
        for prop, items in by_prop.iteritems():
            by_event = defaultdict(Counter)
            for item in items:
                key = item["event"]
                vals = {"count": item["count"]}
                by_event[key].update(vals)
            by_prop[prop] = OrderedDict(sorted(by_event.items(), key=lambda x: x[1], reverse=True))
        return by_prop

    #
    # get segment data
    #
    def get_segment_data(self, event_name, start_date, end_date, unit, event_type, group_by="", where_cond="", viz="bar"):
      # get funnel data segment_data = 
      request_object = {'event' : event_name,
        'from_date': start_date, 
        'to_date': end_date, 
        'unit': unit, 
        'type': event_type }
      #print request_object
      if group_by:
        request_object["on"] = group_by

      if where_cond:
        request_object["where"] = where_cond
      #print request_object
      segment_data = self.mp.request(['segmentation'], request_object) 
      return self.transform_segment_data(event_name, segment_data)

    #
    # transform segment data
    #

    #
    # transform segment  data
    #
    def transform_segment_data(self, event_name, segment_data, table_view=False, viz="bar"):
      # first bring all events for a property value under one list
      #by_prop = defaultdict(list)
      data = defaultdict(list)
      for prop, items in segment_data["data"]["values"].iteritems():
        data["categories"].append(prop)
        data["series"].append(sum(items.values()))
      return data

    #
    # get retention data
    #
    def get_retention_data(self, born_event, start_date, end_date, unit, interval_count, data_as='number', return_event=None, group_by="", where_cond="", viz="bar"):
      # get funnel data segment_data = 
      request_object = {'born_event' : born_event,
        'from_date': start_date, 
        'to_date': end_date, 
        'unit': unit, 
        'interval_count': interval_count}
      #print request_object
      if return_event:
        request_object["event"] = return_event

      if where_cond:
        request_object["where"] = where_cond
      #print request_object
      retention_data = self.mp.request(['retention'], request_object) 
      return self.transform_retention_data(retention_data, unit, data_as)

    #
    # transform segment  data
    #
    def transform_retention_data(self, retention_data, unit, data_as='number', viz="bar"):
      # first bring all events for a property value under one list
      table_data = []
      for prop, items in retention_data.iteritems():
        data = OrderedDict()
        data[unit] = prop
        data['users'] = items["first"]
        for index, ele in enumerate(items["counts"]):
          if data_as == 'number':
            data["".join([unit, str(index)])] = ele
          else:
            data["".join([unit, str(index)])] = round(ele * 100.0 / items["first"], 1)
        table_data.append(data)
      return table_data