#! /usr/bin/env python

# a simple webserver that offers remote control options 
# as an iphone web app

# TODO: security!


# mru, 2011-02


import sys, os, platform, shutil
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
from mako.template import Template
import dbus


class Commands:

    @staticmethod
    def totem_pause():
        """Play/Pause"""
        bus = dbus.SessionBus()
        proxy = bus.get_object('org.mpris.Totem',
                               '/Player')
        proxy.Pause(dbus_interface="org.freedesktop.MediaPlayer")

    @staticmethod
    def totem_next():
        """Next"""
        bus = dbus.SessionBus()
        proxy = bus.get_object('org.mpris.Totem',
                               '/Player')
        proxy.Next(dbus_interface="org.freedesktop.MediaPlayer")

    @staticmethod
    def totem_prev():
        """Prev"""
        bus = dbus.SessionBus()
        proxy = bus.get_object('org.mpris.Totem',
                               '/Player')
        proxy.Prev(dbus_interface="org.freedesktop.MediaPlayer")


    @staticmethod
    def standby():
        """Standby"""
        bus = dbus.SystemBus()
        proxy = bus.get_object('org.freedesktop.UPower',
                               '/org/freedesktop/UPower')
        proxy.Suspend(dbus_interface="org.freedesktop.UPower")

    @staticmethod
    def vol_down():
        """Vol -"""
        os.system("amixer set Master 5%-")

    @staticmethod
    def vol_up():
        """Vol +"""
        os.system("amixer set Master 5%+")

    @staticmethod
    def mute():
        """Mute"""
        if os.system("amixer get Master mute | grep '\[on\]' > /dev/null") != 0:
            os.system("amixer -q set Master unmute")
        else:
            os.system("amixer -q set Master mute")

# #!/bin/bash
# # amarok.sh collection of dbus shortcuts to control Amarok 2.x in a terminal session

# case "$1" in
#   'initialize') # Works only when started like this '. bin/amarok.sh initialize'
# # otherwise the exported variables will be destroyed with termination of skript
#      SESSIONID=$(ls .dbus/session-bus);
#      export `cat .dbus/session-bus/$SESSIONID | grep DBUS_SESSION_BUS_ADDRESS=`;
#      export `cat .dbus/session-bus/$SESSIONID | grep DBUS_SESSION_BUS_PID=`;
#      export `cat .dbus/session-bus/$SESSIONID | grep DBUS_SESSION_BUS_WINDOWID=`;
#   ;;
#   'play') dbus-send --type=method_call --dest=org.kde.amarok /Player org.freedesktop.MediaPlayer.Play;;
#   'pause') dbus-send --type=method_call --dest=org.kde.amarok /Player org.freedesktop.MediaPlayer.Pause;;
#   'next') dbus-send --type=method_call --dest=org.kde.amarok /Player org.freedesktop.MediaPlayer.Next;;
#   'previous') dbus-send --type=method_call --dest=org.kde.amarok /Player org.freedesktop.MediaPlayer.Prev;;
#   'stop') dbus-send --type=method_call --dest=org.kde.amarok /Player org.freedesktop.MediaPlayer.Stop;;
#   'quit') dbus-send --type=method_call --dest=org.kde.amarok / org.freedesktop.MediaPlayer.Quit;;
#   'louder') qdbus org.kde.amarok /Player VolumeSet $(($(qdbus org.kde.amarok /Player VolumeGet) + 5));;
#   'quiet') qdbus org.kde.amarok /Player VolumeSet $(($(qdbus org.kde.amarok /Player VolumeGet) - 5));;
#   'jump+') qdbus org.kde.amarok /Player PositionSet $(($(qdbus org.kde.amarok /Player PositionGet) + 5000));;
#   'jump-') qdbus org.kde.amarok /Player PositionSet $(($(qdbus org.kde.amarok /Player PositionGet) - 5000));;
#   *) echo "No valid parameter. Parameters are play, pause, next, previous, stop, quit, louder, quiet, jump+, jump-"
# esac

css = """
body {
  text-align: center;
  background-color: #ddd; /* Background color */
  color: #222;            /* Foreground color used for text */
  font-family: Helvetica;
  font-size: 14px;
  margin: 0;      /* Amount of negative space around the outside of the body */
  padding: 0;     /* Amount of negative space around the inside of the body */
}

h1 {
  margin: 0;
  padding: 0;
  background-color: #ccc;
  border-bottom: 1px solid #666;
  color: #222;
  display: block;
  font-size: 20px;
  font-weight: bold;
  padding: 10px 0;
  text-align: center;
  text-decoration: none;
  text-shadow: 0px 1px 0px #fff;
  background-image: -webkit-gradient(linear, left top, left bottom,
                                       from(#ccc), to(#999));
}

h2 {
  margin: 0;
  padding: 0;
  background-color: #ccc;
  border-bottom: 1px solid #666;
  color: #def;
  display: block;
  font-size: 18px;
  font-weight: bold;
  padding: 8px 0;
  text-align: center;
  text-decoration: none;
  text-shadow: 0px 1px 0px #222;
  background-image: -webkit-gradient(linear, left top, left bottom,
                                       from(#024FC2), to(#234E8E));
}

table {
  margin: 10px;
  padding: 0;
  width: 90%;
}

.status_error {
background-color: red;
color: black;
font-size: 10px;
}

.status_success {
background-color: blue;
color: black;
font-size: 10px;
}

td {
  -webkit-border-radius: 8px;

  background-color: #FFFFFF;
  border: 1px solid #999999;
  color: #222222;
  display: block;
  font-size: 17px;
  font-weight: bold;
  margin-bottom: -1px;
  padding: 12px 10px;
  text-decoration: none;
  text-align: center;
}
"""

javascript = """
    var request = false;
    var xmlHttpTimeout = null;
    request = new XMLHttpRequest();
    request.onreadystatechange=function() {
      if (request.readyState==4) {
        var status = document.getElementById("statusbar");
        if (request.status == 200) {
          status.innerHTML='<div class="status_success"></div>';
        }
        else {
          status.innerHTML='<div class="status_error">'+request.responseText+'</div>';
        }
      }
    }
    function exec(op, do_confirm) {
      really = true;
      if (do_confirm ) {
        really = confirm('Really execute?');
      }
      if (really) {
        request.open("GET", "/do/"+op, true);
        request.send();
      }
    }
"""

manifest="""CACHE MANIFEST
/style.css
/remote.js
/touch-icon-iphone4.png
"""

# marking as html5 does not work, then
# table colspan goes wrong.
# temporarily disable doctype
# <!DOCTYPE html>

content = Template("""
<html lang="en" manifest="/cache.manifest">
 <head>
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="viewport" content="user-scalable=no, width=device-width" />
  <link rel="stylesheet" type="text/css" href="style.css"/>
  <link rel="apple-touch-icon" sizes="114x114" href="touch-icon-iphone4.png" />
  <title>Remote Control: ${nodename}</title>
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <script type="text/javascript" src="remote.js"></script>
 </head>

<body>

<h1>Remote Control: ${nodename}</h1>
<div id="statusbar"></div>
<h2>Audio</h2>

 <table>
  <tr>
   ${link("vol_down")}
   ${link("vol_up")}
  <tr>
   ${link("mute", colspan=2)}
 </table>

<h2>Totem</h2>

 <table>
  <tr>
   ${link("totem_prev")}
   ${link("totem_next")}
  <tr>
   ${link("totem_pause", colspan=2)}
 </table>

<h2>Power</h2>

 <table>
  <tr>
   ${link("standby",confirm=True)}
 </table>

 </body>
</html>
<%def name="link(fun,colspan=1,confirm=False)">
<%
f = getattr(Commands, fun)
assert callable(f)
%>
<td colspan="${colspan}" onClick="exec('${fun}', ${str(confirm).lower()}); return false">${getattr(Commands, fun).__doc__}</td>
</%def>

""").render(Commands=Commands, nodename=platform.node())



class MyHandler(SimpleHTTPRequestHandler):
    protocol = "HTTP/1.0"

    def do_GET(self):
        print "get", self.path

        def read(filename):
            return open(filename, 'r').read()

        def resp(code, mime, text):
            self.send_response(code)
            self.send_header("Content-type", mime)
            self.end_headers()
            self.wfile.write(text)

        if self.path == "/":
            resp(200, "text/html", content)
            return

        if self.path == "/style.css":
            resp(200, "text/css", css)
            return

        if self.path == "/cache.manifest":
            resp(200, "text/cache-manifest", manifest)
            return

        if self.path == "/touch-icon-iphone4.png":
            resp(200, "image/png", open('remote.png', 'r').read())
            return

        if self.path == "/remote.js":
            resp(200, "text/javascript", javascript)
            return

        if self.path.startswith("/do/"):

            try:
                name = self.path.replace("/do/", "")
                getattr(Commands, name)()
                resp(200, "text/html", "success")
            except Exception, e:
                resp(500, "text/html", "failure: invalid function"+str(e))
                print "invalid function", e
        else:
            resp(404, "text/html", "failure: location not found")
            print "location not available:", self.path
            return


server_address = ('0.0.0.0', 8003)
httpd = BaseHTTPServer.HTTPServer(server_address, MyHandler)

sa = httpd.socket.getsockname()
print "Serving on", sa[0], "port", sa[1]
httpd.serve_forever()
