
#!/usr/bin/python
####################################################################################################

from __future__ import print_function
import urllib, urllib2, httplib, json, time, subprocess, math, sys, os, random, getopt, re, threading, Image
from subprocess import Popen, PIPE
from Adafruit_Thermal import *
from bottle import get, post, request, run, static_file, template
from xml.dom.minidom import parseString
from xml.etree import ElementTree as etree



####################################################################################################




####################################################################################################

@get('/')
def index():
    return '''
        <!DOCTYPE html>
        <html>
        <head>
            <title>Notes & Lists</title>          
             <style>
                body
                    {
                    background: url(gasgasmask.jpg);
                    color: green;
                    text-align: left;
                    }
            </style>
        </head>
        <body>
            <h1>The Dagedi Personal Digital Assistant</h1> 
            <p><form action='/printstring' method='post'>
                <input name='mytext' type='text' value='Notes or Lists here'>
                <input type='submit' value='Send!'>
            </form></p>

	    <p><form action='/fortune' method='post'>
                <input type='submit' value='Fortune!'>
            </form><p/>

            <p><form action='/forecast' method='post'>
                <input type='submit' value='Weather!'>
            </form><p/>

            <p><form action='/calculator' method='post'>
                <input name='mymath' type='text' value='Basic Math *=x'>
                <input type='submit' value='Calculate!'>
            </form><p/>
            
	    <p><form action='/timer' method='post'>
                <input name='time' type='text' value='eg; 1h 20m 22s'>   <input name='alarmtype' type='text' value='timer msg'>
                <input type='submit' value='Set Timer!'>
            </form><p/>

            <p><form action='/sodoku' method='post'>
                <input type='submit' value='Sodoku!'>
            </form><p/>

            <p><form action='http://73.240.49.250:3000/'>
                <input type='submit' value='Pandora!'></form> <form action='/songinfo' method='post'><input type='submit' value='PrintPandoraInfo'></form><p/>
            
            <p><form action='/kndy' method='post'>
                <input type='submit' value='PLAY K N D Y!'>
            </form><p/>

            <p><form action='/kndyquit' method='post'>
                <input type='submit' value='QUIT K N D Y!'>
            </form><p/>

            <p><form action="http://www.reddit.com/">
                <input type='submit' value='Reddit!'>
            </form><p/>
            <p><form action="http://www.facebook.com/">
                <input type='submit' value='facebook :('>
            </form><p/>
            <p><form action="http://www.fark.com/">                                                  
                <input type='submit' value='Fark News!'>
            </form><p/>
            <p><form action="https://www.google.com/#q=max+tavern+eugene+reviews">                     
                <input type='submit' value='Max s  Reviews!'>
            </form><p/>                                                                                 
            <p><form action="https://www.google.com/#q=ambrosia+eugene+reviews">                   
                <input type='submit' value='Ambrosia Reviews!'>
            </form><p/>
<iframe src="https://duckduckgo.com/search.html?width=150&prefill=Search&bgcolor=000000" style="overflow:hidden;margin:0;padding:0;width:200px;height:25px;" frameborder="0"></iframe>
                 
            </body>
        </html>
    '''

####################################################################################################

@post('/printstring')
def printstring():
    printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
    mytext  = request.forms.get('mytext')

    printer.boldOn()
    printer.print(mytext)
    printer.boldOff()

    printer.feed(2)
    printer.sleep()
    printer.wake()

    return template('''
        <p>printing <b>{{ message }}</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''', message = mytext)

####################################################################################################

@post('/fortune')
def fortune():
    printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
    text    = urllib.urlopen('http://fortunecookieapi.com/v1/cookie?lottoId=0&lessonId=0')
    obj     = json.load(text)[0];

    printer.boldOn()
    printer.print(obj['fortune']['message'])
    printer.boldOff()

    printer.feed(2)
    printer.sleep()
    printer.wake()

    return template('''
        <p>printing <b>{{ message }}</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''', message = obj)

   
####################################################################################################

@post('/forecast')
def forecast():
    printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
    dom     = parseString(urllib.urlopen('http://weather.yahooapis.com/forecastrss?w=2400539').read())
    deg     = chr(0xf8)

    # print heading

    printer.inverseOn()
    printer.print('{:^32}'.format(dom.getElementsByTagName('description')[0].firstChild.data))
    printer.inverseOff()

    # print current conditions

    printer.boldOn()
    printer.print('{:^32}'.format('Current conditions:'))
    printer.boldOff()

    printer.print('{:^32}'.format(dom.getElementsByTagName('pubDate')[0].firstChild.data))

    temp = dom.getElementsByTagName('yweather:condition')[0].getAttribute('temp')
    cond = dom.getElementsByTagName('yweather:condition')[0].getAttribute('text')

    printer.print(temp)
    printer.print(deg)
    printer.println(' ' + cond)

    # print forecast

    printer.boldOn()
    printer.print('{:^32}'.format('Forecast:'))
    printer.boldOff()

    forecast_idx(printer, dom, 0)
    forecast_idx(printer, dom, 1)

    printer.feed(2)
    printer.sleep()
    printer.wake()

    return template('''
        <p>printing <b>{{ message }}</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''', message = format)

####################################################################################################

def forecast_idx(printer, dom, idx):
    tag  = 'yweather:forecast'
    deg  = chr(0xf8)
    day  = dom.getElementsByTagName(tag)[idx].getAttribute('day')
    lo   = dom.getElementsByTagName(tag)[idx].getAttribute('low')
    hi   = dom.getElementsByTagName(tag)[idx].getAttribute('high')
    cond = dom.getElementsByTagName(tag)[idx].getAttribute('text')

    printer.print(day + ': low ' + lo)
    printer.print(deg)
    printer.print(' high ' + hi)
    printer.print(deg)
    printer.println(' ' + cond)

####################################################################################################

@post('/calculator')
def calculator():
    printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
    mymath  = request.forms.get('mymath')
    math    = subprocess.Popen(['bc', '-i', '-q'], stdin = subprocess.PIPE, stdout = subprocess.PIPE)
    result  = math.communicate(mymath + "\nquit")[0].rstrip()
	
    printer.boldOn()
    printer.print(result)
    printer.boldOff()

    printer.feed(2)
    printer.sleep()
    printer.wake()

    return template('''
        <p>printing <b>{{ message }}</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''', message = mymath)
    
####################################################################################################
@post('/sodoku')
def sodoku():
  printer = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
  printer.setLineHeight(24) # So graphical chars fit together
  args = sys.argv[1:]
  if len(args) > 0:
    puzzles = [loadboard(filename) for filename in args]
  else:
    puzzles = [makepuzzle(solution([None] * 81))]
  for puzzle in puzzles:
    printer.println("PUZZLE:")
    printer.feed(1)
    printer.print(printboard(puzzle))
    printer.feed(1)
    printer.println("RATING:", ratepuzzle(puzzle, 4))
    if len(args) > 0:
      printer.println()
      printer.println("SOLUTION:")
      answer = solution(puzzle)
      if answer is None: printer.println("NO SOLUTION")
      else: printer.print(printboard(answer))
  printer.feed(3)

def makepuzzle(board):
  puzzle = []; deduced = [None] * 81
  order = random.sample(xrange(81), 81)
  for pos in order:
    if deduced[pos] is None:
      puzzle.append((pos, board[pos]))
      deduced[pos] = board[pos]
      deduce(deduced)
  random.shuffle(puzzle)
  for i in xrange(len(puzzle) - 1, -1, -1):
    e = puzzle[i]; del puzzle[i]
    rating = checkpuzzle(boardforentries(puzzle), board)
    if rating == -1: puzzle.append(e)
  return boardforentries(puzzle)

def ratepuzzle(puzzle, samples):
  total = 0
  for i in xrange(samples):
    state, answer = solveboard(puzzle)
    if answer is None: return -1
    total += len(state)
  return float(total) / samples

def checkpuzzle(puzzle, board = None):
  state, answer = solveboard(puzzle)
  if answer is None: return -1
  if board is not None and not boardmatches(board, answer): return -1
  difficulty = len(state)
  state, second = solvenext(state)
  if second is not None: return -1
  return difficulty

def solution(board):
  return solveboard(board)[1]

def solveboard(original):
  board = list(original)
  guesses = deduce(board)
  if guesses is None: return ([], board)
  track = [(guesses, 0, board)]
  return solvenext(track)

def solvenext(remembered):
  while len(remembered) > 0:
    guesses, c, board = remembered.pop()
    if c >= len(guesses): continue
    remembered.append((guesses, c + 1, board))
    workspace = list(board)
    pos, n = guesses[c]
    workspace[pos] = n
    guesses = deduce(workspace)
    if guesses is None: return (remembered, workspace)
    remembered.append((guesses, 0, workspace))
  return ([], None)

def deduce(board):
  while True:
    stuck, guess, count = True, None, 0
    # fill in any spots determined by direct conflicts
    allowed, needed = figurebits(board)
    for pos in xrange(81):
      if None == board[pos]:
        numbers = listbits(allowed[pos])
        if len(numbers) == 0: return []
        elif len(numbers) == 1: board[pos] = numbers[0]; stuck = False
        elif stuck:
          guess, count = pickbetter(guess, count, [(pos, n) for n in numbers])
    if not stuck: allowed, needed = figurebits(board)
    # fill in any spots determined by elimination of other locations
    for axis in xrange(3):
      for x in xrange(9):
        numbers = listbits(needed[axis * 9 + x])
        for n in numbers:
          bit = 1 << n
          spots = []
          for y in xrange(9):
            pos = posfor(x, y, axis)
            if allowed[pos] & bit: spots.append(pos)
          if len(spots) == 0: return []
          elif len(spots) == 1: board[spots[0]] = n; stuck = False
          elif stuck:
            guess, count = pickbetter(guess, count, [(pos, n) for pos in spots])
    if stuck:
      if guess is not None: random.shuffle(guess)
      return guess

def figurebits(board):
  allowed, needed = [e is None and 511 or 0 for e in board], []
  for axis in xrange(3):
    for x in xrange(9):
      bits = axismissing(board, x, axis)
      needed.append(bits)
      for y in xrange(9):
        allowed[posfor(x, y, axis)] &= bits
  return allowed, needed

def posfor(x, y, axis = 0):
  if axis == 0: return x * 9 + y
  elif axis == 1: return y * 9 + x
  else: return ((0,3,6,27,30,33,54,57,60)[x] + (0,1,2,9,10,11,18,19,20)[y])

def axisfor(pos, axis):
  if axis == 0: return pos / 9
  elif axis == 1: return pos % 9
  else: return (pos / 27) * 3 + (pos / 3) % 3

def axismissing(board, x, axis):
  bits = 0
  for y in xrange(9):
    e = board[posfor(x, y, axis)]
    if e is not None: bits |= 1 << e
  return 511 ^ bits
  
def listbits(bits):
  return [y for y in xrange(9) if 0 != bits & 1 << y]

def allowed(board, pos):
  bits = 511
  for axis in xrange(3):
    x = axisfor(pos, axis)
    bits &= axismissing(board, x, axis)
  return bits

def pickbetter(b, c, t):
  if b is None or len(t) < len(b): return (t, 1)
  if len(t) > len(b): return (b, c)
  if random.randint(0, c) == 0: return (t, c + 1)
  else: return (b, c + 1)

def entriesforboard(board):
  return [(pos, board[pos]) for pos in xrange(81) if board[pos] is not None]

def boardforentries(entries):
  board = [None] * 81
  for pos, n in entries: board[pos] = n
  return board

def boardmatches(b1, b2):
  for i in xrange(81):
    if b1[i] != b2[i]: return False
  return True

def printboard(board):
  # Top edge of board:
  out = ('      '
       + chr(0xC9) # Top left corner
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xCB) # Top 'T' (double)
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xCB) # Top 'T' (double)
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xD1) # Top 'T'
       + chr(0xCD) # Top edge
       + chr(0xBB) # Top right corner
       + '\n')
  for row in xrange(9):
    out += ('      ' + chr(0xBA)) # Double Bar
    for col in xrange(9):
      n = board[posfor(row, col)]
      if n is None:
        out += ' '
      else:
        out += str(n+1)
      if (col == 2) or (col == 5) or (col == 8):
        out += chr(0xBA) # Double bar
      else:
        out += chr(0xB3) # Single bar
    out += '\n'
    if(row < 8):
      if(row == 2) or (row == 5):
        out += ('      '
              + chr(0xCC) # Left 'T' (double)
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xCE) # Double +
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xCE) # Double +
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xD8) # +
              + chr(0xCD) # Horizontal bar
              + chr(0xB9) # Right 'T' (double)
              + '\n')
      else:
        out += ('      '
              + chr(0xC7) # Left 'T'
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xD7) # Double +
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xD7) # Double +
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xC5) # +
              + chr(0xC4) # Horizontal bar
              + chr(0xB6) # Right 'T'
              + '\n')
  out += ('      '
        + chr(0xC8) # Bottom left corner
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xCA) # Bottom 'T' (double)
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xCA) # Bottom 'T' (double)
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xCF) # Bottom 'T'
        + chr(0xCD) # Bottom edge
        + chr(0xBC) # Bottom-right corner
        + '\n')

# Original output code:
#  out = ""
#  for row in xrange(9):
#    for col in xrange(9):
#      out += (""," "," ","  "," "," ","  "," "," ")[col]
#      out += printcode(board[posfor(row, col)])
#    out += ('\n','\n','\n\n','\n','\n','\n\n','\n','\n','\n')[row]
  return out

def parseboard(str):
  result = []
  for w in str.split():
    for x in w:
      if x in '|-=+': continue
      if x in '123456789': result.append(int(x) - 1)
      else: result.append(None)
      if len(result) == 81: return result

def loadboard(filename):
  f = file(filename, 'r')
  result = parseboard(f.read())
  f.close()
  return result

def basedir():
  if hasattr(sys.modules[__name__], '__file__'):
    return os.path.split(__file__)[0]
  elif __name__ == '__main__':
    if len(sys.argv) > 0 and sys.argv[0] != '':
      return os.path.split(sys.argv[0])[0]
    else:
      return os.curdir

def loadsudokutemplate(ext):
  f = open(os.path.join(basedir(), 'sudoku-template.%s' % ext), 'r')
  result = f.read()
  f.close()
  return result
  
  return template('''
        <p>Printing Random Sodoku!</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''')

####################################################################################################

@post('/timer')
def timer():
    at      = request.forms.get('alarmtype')
    tm      = request.forms.get('time')
    wtf     = "sleep " + tm + " && espeak \"" + at + "\""
    input   = subprocess.Popen(['/bin/bash', '-c', wtf])
    
    return template('''
         <p>Timer set for:<b>{{ message }}</b>!</p>
            <style>
                body
                    {
                    background: url(time.jpg);
                    color: white;
                    text-align: left;
                    }
            </style>
        <p>go <a href='/'>back</a>.</p>
        ''', message = tm)


####################################################################################################

@post('/kndyquit')
def kndyquit():
    tunes    = subprocess.Popen(['killall', 'mplayer'])
    
    return template('''
        <p><b>Killing K N D Y!</p>
            <style>
                body
                    {
                    background: url(music.jpg);
                    color: white;
                    text-align: left;
                    }
            </style>
        <p>go <a href='/'>back</a>.</p>
        ''')

####################################################################################################

@post('/kndy')
def kndy():
    tunes    = subprocess.Popen(['mplayer', 'http://ushroo.com:1776/listen.ogg'])

    return template('''
        <head><b>
            <title>Playing K N D Y!</title></b>
            <style>
                body
                    {
                    background: url(music.jpg);
                    color: white;
                    text-align: left;
                    }
            </style>
        </head>
        <p><b>Playing K N D Y!</p>
        <p>go <a href='https://ushroo.com/kndy'>K N D Y Control</a>.</p>
        ''')

####################################################################################################

@post('/pandora')
def pandora():
 return template('''
        <p><b>Pandora!</p>
            <style>
                body
                    {
                    background: url(music.jpg);
                    color: white;
                    text-align: left;
                    }
            </style>

        <p>To Pandora<a href='http://73.240.49.250:3000/'>Portal!</a></p>
        ''')    

####################################################################################################

@post('/songinfo')
def songinfo():
    printer    = Adafruit_Thermal("/dev/ttyAMA0", 19200, timeout = 5)
    file       = open('/root/.config/pianobar/currentSong', 'r')
    str        = file.read()
    aas        = str.split(",")

    for list in aas:
    	printer.boldOn()
    	printer.print(list)
    	printer.boldOff()

    	printer.feed(2)
    	printer.sleep()
    	printer.wake()
    return template('''
        <p>printing <b>{{ message }}</b>!</p>
        <p>go <a href='/'>back</a>.</p>
        ''', message = list)




####################################################################################################

@get('/<filename>')
def server_static(filename):
    return static_file(filename, root = '.')

####################################################################################################

run(host = '0.0.0.0', port = 80, debug = True)

####################################################################################################
