#!/usr/bin/python

from slackclient import SlackClient
import os
import sys
from optparse import OptionParser

import json
import fileinput
import random
import re
import time as systime
import threading

import formatter
import kchat
import kvincent
import inflect

### config

p = inflect.engine()
tokenfile = open("slack4token", 'r')
for x in tokenfile:
  token = x.rstrip()

sc = SlackClient(token)
botname = "kvincent_"

### slack API handling

def collection(type): # stupid hardcoding types from api for get_target
  if type == "users":
    return 'members'
  elif type == "im":
    return 'ims'
  else:
    return type

def get_target(name, type, source, target):
  # returns value of <target> when given value <name> of field <source> of
  # collective <type> from a .list method
  # valid types: "channels", "users", "im", "reactions", "groups", "emoji"

  # sample: get_target(chanName, "channels", "name", "id") will return the id
  # of channel channel called chanName

  for x in json.loads(sc.api_call(type+".list"))[collection(type)]:
    if x[source] == name:
      return x[target]

  print name + " not found"
  return ""

def list_channels(): #print list of channels bot is in
  print "channels:"

  for data in json.loads(sc.api_call("channels.list"))["channels"]:
    if data['is_member']:
      print data['name']+" ("+data['id']+")"

  print "pms:"

  for data in json.loads(sc.api_call("im.list"))["ims"]:
    print get_target(data['user'], "users", "id", "name")+" ("+data['id']+")"

def open_msg(nick): # opens im with nick
  print sc.api_call("im.open", user=get_target(nick, "users", "name", "id"))

### SHORTCUT HELPERS
def get_nick(msg_raw): # retrieve nick from raw message
  return get_target(msg_raw['user'], "users", "id", "name")

def get_time(msg_raw): # retrieve time from raw message
  return systime.localtime(float(msg_raw['ts']))

### helper functions

def irc_style(msg_raw): #makes an irssi-like line
  return systime.strftime("%H:%M", get_time(msg_raw))+" < "+get_nick(msg_raw)+"> "+msg_raw['text']

def log_line(channel, date, line): #line should to be irc_style
  logfile = open("klogs/slack/#"+channel+" slack"+date+".txt", 'a')
  logfile.write(line+"\n")
  logfile.close()
  return line

def log_toggle(channel, time, opening): #toggles log status
  if opening:
    verb = "opened"
  else:
    verb = "closed"

  logMsg = "--- Log "+verb+systime.strftime(" %a %b %d %H:%M:%S %Y", time)

  date = systime.strftime("%Y-%m-%d", time)
  log_line(channel, date, logMsg)

  return "log "+verb

def process_file(msg_raw): #do something with uploaded file
  data = msg_raw['file']
  url = data['url']
  print url
  pm("modgethanc", "pics! "+url)

def is_pm(msg_raw): #determine if a message is a pm; SUPER UGLY
  #channelID = msg_raw['channel']

  for x in json.loads(sc.api_call("im.list"))["ims"]:
    if x['id'] == msg_raw['channel']:
      return True

  return False

def is_listen(msg_raw, chan): #determine if a message is in a targeted channel
  return msg_raw['channel'] == get_target(chan, "channels", "name", "id")

### chat functions

def say(chan, msg, nick=""):
  if nick:
    msg = "@" + nick + " " + msg

  sc.api_call("chat.postMessage", channel=get_target(chan, "channels", "name", "id"), text=msg, as_user="true")

  return msg

def multisay(chan, msglist, nick=""):
 for x in msglist:
   say(chan, x, nick)

def multipm(nick, msglist):
  for x in msglist:
    pm(nick, x)

def pm(nick, msg):
  id = get_target(nick, "users", "name", "id")
  chan = get_target(id, "im", "user", "id")

  sc.api_call("chat.postMessage", channel=chan, text=msg, as_user="true")

###

def listen(chan):
  if sc.rtm_connect():
    time = systime.localtime()
    date = systime.strftime("%Y-%m-%d",time)
    log_toggle(chan, systime.localtime(), True)
    sc.api_call("users.setPresence", presence="auto")
    say(chan, kchat.say('enter'))

    while True:
      time = systime.localtime()
      date = systime.strftime("%Y-%m-%d",time)

      try:
        msglist = sc.rtm_read()
        for msg_raw in msglist:
          print msg_raw
          msgType = msg_raw['type']
          #print msgType
          nick = get_target(msg_raw['user'], "users", "id", "name")
          if msgType == 'message':
            ## extracting info to more readable names
            ts   = float(msg_raw['ts'])
            time = systime.localtime(ts)
            date = systime.strftime("%Y-%m-%d", time)
            msg  = msg_raw['text']
            msgChan = get_target(msg_raw['channel'], "channels", "id", "name")
            #print irc_style(msg_raw)
            log_line(msgChan, date, irc_style(msg_raw))
            #if (is_listen(msg_raw, chan) or is_pm(msg_raw)):
            if 1: # this is temporary
              if not nick == botname:
                if re.match('^<@U0F597CKE', msg):
                   multisay(chan, kvincent.addressed(chan, nick, ts, msg, "slack"), nick)
                elif is_pm(msg_raw):
                   multipm(nick, kvincent.addressed(chan, nick, ts, msg, "slack"))
                else:
                  multisay(chan, kvincent.said(chan, nick, ts, msg, "slack"), nick)
          if msgType == 'file_shared':# and not nick == "modgethanc":
            pm("modgethanc", "looking for pic...")
            process_file(msg_raw)
        systime.sleep(1)

      except KeyboardInterrupt:
        print "killed"
        log_line(chan, date, systime.strftime("%H:%M", time)+" < kvincent_> "+say(chan, kchat.say('sleep')))
        sc.api_call("users.setPresence", presence="away")
        log_toggle(chan, systime.localtime(), False)
        return

      except:
        #print "died"
        #log_line(chan, date, systime.strftime("%H:%M", time)+" < kvincent_> "+say(chan, "goodbye cruel world"))
        #sc.api_call("users.setPresence", presence="away")
        #log_toggle(chan, systime.localtime(), False)
        continue

  else:
    print "nak"

