<%pre>

#include <setup.h>
#include <tools.h>
#include <users.h>

#include <vdr/remote.h>
#include <vdr/device.h>

using namespace vdrlive;

bool IsGrabImageAvailable() {
  cDevice* device = cDevice::PrimaryDevice();
  if (!device) return false;
  int size = 0;
  uchar* image = device->GrabImage(size, true, 80, 729, 480);
  if (!image) return false;
  free(image);
  return true;
}

</%pre>
<%args>
  int channel = -1;
</%args>
<%session scope="global">
bool logged_in(false);
</%session>
<%request scope="global">
  tChannelID channelID;
</%request>
<%include>page_init.eh</%include>
<{
if (!logged_in && LiveSetup().UseAuth()) {
  cToSvConcat targetUrl("/login.html?redirect=");
  targetUrl.appendUrlEscaped(request.getQuery());
  return reply.redirect(targetUrl.data());
}
}>
<%cpp>
  if (!cUser::CurrentUserHasRightTo(UR_USEREMOTE))
    throw HtmlError( tr("Sorry, no permission. Please contact your administrator!") );

  pageTitle = tr("Remote Control");

  {
    const cChannel* Channel = nullptr;
    LOCK_CHANNELS_READ;
    if (channel > 0) {
      Channel = Channels->GetByNumber(channel);
    } else {
      if (cDevice::CurrentChannel()) {
        Channel = Channels->GetByNumber(cDevice::CurrentChannel());
      } else {
        Channel = Channels->Get(Channels->GetNextNormal( -1 ));
      }
    }
    if (!Channel)
      throw HtmlError( tr("Couldn't find channel or no channels available. Maybe you mistyped your request?") );
    channelID = Channel->GetChannelID();
  }
</%cpp>
<& pageelems.doc_type &>
<html>
  <head>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>VDR-Live - <$ pageTitle $></title>
  <& pageelems.stylesheets &>
  <& pageelems.ajax_js &>
  <script type="text/javascript"><!--
  var newImg = null;
  var imgsrc = "";
  var osdAjax = null;
  var osdTimeout = -1;
  var interval = -1;
  var clkTimer;

  function changeScreenContent(){
    var screenCon= document.getElementsByName('screenCon');
    for ( var i=0; i < screenCon.length; i++){
      if (screenCon[i].id == 'screenCon_grab'){
        if (screenCon[i].checked){
          newImg = new Image();
          StreamLoad();
          ChangeInterval();
          StreamLoad();
          document.images.vdrlive.style.display= '';
        } else {
          window.clearInterval(interval);
          document.images.vdrlive.style.display= 'none';
          newImg = null;
        }
      } else if (screenCon[i].id == 'screenCon_osd'){
        if (screenCon[i].checked){
          osdAjax= new Ajax('osd.xml', {method: 'get'});
          osdAjax.lastUpd= -1;
          osdAjax.addEvent('onComplete', function(text,xmlDoc){
            try{
              var upd = parseInt(text.match(/data-time="(\\d+)"/)[1]);
              if ( osdAjax.lastUpd != upd ){
                $('osd').empty().setHTML(text);
                osdAjax.lastUpd = upd;
                var sOsdItems= $$('#screenshot .osdItems');
                var sSelected= $$('#screenshot .selected');
                if (sOsdItems.length > 0 && sSelected.length > 0) sOsdItems[0].scrollTop= sSelected[0].offsetTop - 40;
              }
            } catch (e) {}
            window.clearInterval(osdTimeout);
            osdTimeout= window.setTimeout("OSDLoad()",1000);
          });
          document.getElementById('osd').style.display= '';

          OSDLoad()
        } else {
          document.getElementById('osd').style.display= 'none';
          osdAjax= null;
        }
      } else if (screenCon[i].id == 'screenCon_none'){
        if (screenCon[i].checked) {
          document.getElementById('screenshot').style.display= 'none';
          document.getElementById('remoteDiv').style.transform= 'scale(1.4)';
          document.getElementById('remoteDiv').style.transformOrigin= 'left top';
        } else {
          document.getElementById('screenshot').style.display= '';
          document.getElementById('remoteDiv').style.transform= '';
          document.getElementById('remoteDiv').style.transformOrigin= '';
        }
                              }
    }

  }

  function StreamLoad()
  {
    if (!newImg)
      return;
    uniq = new Date();
    uniq = uniq.getTime();
    document.images.vdrlive.src=newImg.src;
    newImg.src=imgsrc+"?"+uniq;
  }

  function StreamInit()
  {
    document.getElementsByName('screenCon')[0].checked= true;
    if (document.images.vdrlive)
      imgsrc = document.images.vdrlive.src;
    FillIntervals();
    changeScreenContent();
    $('osd').addEvents({
        'click': function(ev){
            $clear(clkTimer);
            clkTimer = (function(){
              handleOSD(ev.target, false);
            }).delay(200, this);
        },
        'dblclick': function(ev){
            $clear(clkTimer);
            handleOSD(ev.target, true);
        }
    });
  }

  function ChangeInterval()
  {
    var element = document.getElementsByName('interval').item(0);
    var timeout = element.value;
    window.clearInterval(interval);
    interval = window.setInterval("StreamLoad()", timeout);
  }

  function StreamEnd()
  {
    window.clearInterval(interval);
  }

  function OSDLoad(){
    if (osdAjax)
      osdAjax.request();
  }
  function selectLineOsd(elem,DonotLoadOSD) {
    var hits= 0,
      cur= elem,
      keycode= <$ kDown $>;
    while (cur && cur.className.indexOf('selected') == -1 ) {
      if (cur.className.indexOf('notSelectable') == -1) hits++;
      cur= cur.previousSibling;
    };
    if (!cur) {
      hits= 0;
      cur= elem;
      keycode= <$ kUp $>;
      while (cur && cur.className.indexOf('selected') == -1 ){
        if (cur.className.indexOf('notSelectable') == -1) hits++;
        cur= cur.nextSibling;
      };
    }
    KeyPress(keycode, DonotLoadOSD, hits);
  }
  function handleOSD(elem, doEnter){
    // since we do not know whether all browsers return the same 'className' pattern
    // for multiple classes, we better eliminate the generic 'odsButton' class
    switch (elem.className.replace(/osdButton(?=\\W|$)/, '').trim()){
    case 'osdButtonRed':
      return KeyPress(<$ kRed $>);
    case 'osdButtonGreen':
      return KeyPress(<$ kGreen $>);
    case 'osdButtonYellow':
      return KeyPress(<$ kYellow $>);
    case 'osdButtonBlue':
      return KeyPress(<$ kBlue $>);
    case 'osdTitle':
      return KeyPress(<$ kBack $>);
    case '':
      if (elem.parentNode.className == 'osdItem') {
        selectLineOsd(elem.parentNode,doEnter);
        if (!doEnter) return false;
        return KeyPress(<$ kOk $>);
      }
      if (elem.parentNode.className == 'osdItem selected') {
        return KeyPress(<$ kOk $>);
      }
      return true;
    case 'osdItem':
      selectLineOsd(elem,doEnter);
      if (!doEnter) return false;
    case 'osdItem selected':
      return KeyPress(<$ kOk $>);
    }
    return true;
  }

  function KeyPress(keycode,DonotLoadOSD=false,repeat=1)
  {
    var req = new Ajax('keypress.xml', { method : 'post'});
    if (!DonotLoadOSD && osdAjax)
      req.addEvent('onComplete', OSDLoad);
    req.request('keycode=' + keycode + '&async=1&repeat='+repeat);
    return false;
  }

  function FillIntervals()
  {
    var element = document.getElementsByName('interval').item(0);
    if (!element)
      return;
    var items = new Array(50, 100, 500, 1000, 2000, 5000);
    element.options.length = items.length;
    for (i = 0; i < items.length; ++i) {
      element.options[i].value = items[i];
      element.options[i].text = (items[i] / 1000) + " s";
      if (items[i] == <$ cToSvInt(LiveSetup().GetScreenshotInterval() ) $>)
        element.selectedIndex = i;
    }
  }

  function KeyboardInput(ev)
  {
// https://www.yavdr.org/documentation/0.7/yaVDR07_documentation.html#vdr -> Tastenbelegung
// https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
    switch (ev.which){
    case 120:                                // F9
    case 9:  return KeyPress(<$ kMenu $>);   // VK_TAB The Horizontal Tab key,
    case 27: return KeyPress(<$ kBack $>);   // VK_ESCAPE The Esc (Escape) key
    case 13: return KeyPress(<$ kOk $>);     // VK_RETURN Enter/Return
    case 38: return KeyPress(<$ kUp $>);     // VK_UP The up arrow key.
    case 40: return KeyPress(<$ kDown $>);   // VK_DOWN The down arrow key
    case 37: return KeyPress(<$ kLeft $>);   // VK_LEFT The left arrow key.
    case 39: return KeyPress(<$ kRight $>);  // VK_RIGHT The right arrow key
    case 112: return KeyPress(<$ kRed $>);   // F1
    case 113: return KeyPress(<$ kGreen $>); // F2
    case 114: return KeyPress(<$ kYellow $>); // F3
    case 115: return KeyPress(<$ kBlue $>);  // F4
    case 116: return KeyPress(<$ kFastRew $>);  // F5
    case 117: return KeyPress(<$ kFastFwd $>);  // F6
    case 121: return KeyPress(<$ kMute $>);  // F10
    case 122: return KeyPress(<$ kVolDn $>); // F11
    case 123: return KeyPress(<$ kVolUp $>); // F12
    case 33: return KeyPress(<$ kChanUp $>); // VK_PRIOR The Page Up (or PgUp) key.
    case 34: return KeyPress(<$ kChanDn $>); // VK_NEXT The Page Down (or PgDn) key.
    case 36: return KeyPress(<$ cToSvInt(kKbd | (kfHome << 16) ) $>); // VK_HOME The Home key (or Pos1)
    case 35: return KeyPress(<$ cToSvInt(kKbd | (kfEnd << 16) ) $>); // VK_END The End key
    case 45: return KeyPress(<$ cToSvInt(kKbd | (kfIns << 16) ) $>); // VK_INSERT The Insert key, Ins
    case 46: return KeyPress(<$ cToSvInt(kKbd | (kfDel << 16) ) $>); // VK_DELETE The Delete key, Del
    case  8: return KeyPress(<$ cToSvInt(kKbd | (0x7F << 16) ) $>); // VK_BACK The Backspace key. This key is labeled Delete on Mac keyboards
    }
    if (ev.key.length == 1) {
      switch (ev.key) {
        case '0': return KeyPress(<$ k0 $>);
        case '1': return KeyPress(<$ k1 $>);
        case '2': return KeyPress(<$ k2 $>);
        case '3': return KeyPress(<$ k3 $>);
        case '4': return KeyPress(<$ k4 $>);
        case '5': return KeyPress(<$ k5 $>);
        case '6': return KeyPress(<$ k6 $>);
        case '7': return KeyPress(<$ k7 $>);
        case '8': return KeyPress(<$ k8 $>);
        case '9': return KeyPress(<$ k9 $>);
      }
      let i_val = ev.key.charCodeAt(0);
      if (i_val > 31 & i_val < 256) {
        return KeyPress(<$ kKbd $> | (i_val << 16));
      }
    }
    return true;
  }
  //--></script>
% reply.sout().imbue(std::locale());
  </head>
  <body onload="StreamInit(); FillIntervals()" onunload="StreamEnd()" onpagehide="saveScrollPosition('remoteDiv')" onpageshow="restoreScrollPosition()" onkeydown="return KeyboardInput(event);">
    <& pageelems.logo &>
    <& menu active="remote" component=("remote.remote_actions")>
    <div id="content"><div id="remoteDiv" class="remote">
      <# set containers to 'display: none' to avoid flickering upon loading #>
      <div id="screenshot" class="screenshot">
%       if (IsGrabImageAvailable() ) {
          <img src="screenshot.jpg" name="vdrlive" />
%       }
        <div id="osd" style="display: none;"></div>
      </div>
      <div>
      <img src="<$ LiveSetup().GetThemedLink("img", "remote_control.png") $>" width="162" height="378" border="0" usemap="#remote" alt="" />
           <map name="remote">
          <area href="#" shape="circle" coords="37,36,10" alt="Power" onclick="return KeyPress(<$ kPower $>)" />
          <area href="#" shape="rect" coords="27,60,59,75" alt="1" onclick="return KeyPress(<$ k1 $>)" />
          <area href="#" shape="rect" coords="64,59,98,75" alt="2" onclick="return KeyPress(<$ k2 $>)" />
          <area href="#" shape="rect" coords="103,59,137,75" alt="3" onclick="return KeyPress(<$ k3 $>)" />
          <area href="#" shape="rect" coords="25,82,60,98" alt="4" onclick="return KeyPress(<$ k4 $>)" />
          <area href="#" shape="rect" coords="65,82,98,99" alt="5" onclick="return KeyPress(<$ k5 $>)" />
          <area href="#" shape="rect" coords="103,83,137,99" alt="6" onclick="return KeyPress(<$ k6 $>)" />
          <area href="#" shape="rect" coords="26,106,60,121" alt="7"  onclick="return KeyPress(<$ k7 $>)" />
          <area href="#" shape="rect" coords="65,105,97,121" alt="8" onclick="return KeyPress(<$ k8 $>)" />
          <area href="#" shape="rect" coords="104,106,137,122" alt="9" onclick="return KeyPress(<$ k9 $>)" />
          <area href="#" shape="rect" coords="66,128,98,144" alt="0" onclick="return KeyPress(<$ k0 $>)" />
          <area href="#" shape="circle" coords="37,157,13" alt="Vol+" onclick="return KeyPress(<$ kVolUp $>)" title="&amp;lt;F12&amp;gt;" />
          <area href="#" shape="circle" coords="37,190,13" alt="Vol-" onclick="return KeyPress(<$ kVolDn $>)" title="&amp;lt;F11&amp;gt;" />
          <area href="#" shape="circle" coords="125,157,13" alt="P+" onclick="return KeyPress(<$ kChanUp $>)" title="&amp;lt;PgUp&amp;gt;" />
          <area href="#" shape="circle" coords="125,190,13" alt="P-" onclick="return KeyPress(<$ kChanDn $>)" title="&amp;lt;PgDn&amp;gt;" />
          <area href="#" shape="circle" coords="81,174,8" alt="Mute" onclick="return KeyPress(<$ kMute $>)" title="&amp;lt;F10&amp;gt;" />
          <area href="#" shape="circle" coords="81,202,11" alt="Record" onclick="return KeyPress(<$ kRecord $>)" />
          <area href="#" shape="poly" coords="39,215,29,227,30,235,39,236,51,222,49,215,43,213" alt="Menu" onclick="return KeyPress(<$ kMenu $>)" title="&amp;lt;Tab&amp;gt;,&amp;lt;F9&amp;gt;" />
          <area href="#" shape="poly" coords="119,213,127,219,135,230,132,235,127,236,119,231,114,223,113,215" alt="Exit" onclick="return KeyPress(<$ kBack $>)" title="&amp;lt;Esc&amp;gt;" />
          <area href="#" shape="poly" coords="33,289,31,298,43,310,51,308,54,300,41,287" alt="Subtitles" onclick="return KeyPress(<$ kSubtitles $>)" />
          <area href="#" shape="poly" coords="131,289,133,298,122,310,112,308,110,300,122,287" alt="Audio" onclick="return KeyPress(<$ kAudio $>)" />
          <area href="#" shape="poly" coords="58,230,70,223,82,223,91,223,105,231,96,240,87,237,78,236,69,240,66,241,58,232" alt="Up" onclick="return KeyPress(<$ kUp $>)" />
          <area href="#" shape="poly" coords="111,237,119,249,121,259,119,275,113,285,109,284,101,276,104,270,107,260,106,253,101,245" alt="Right" onclick="return KeyPress(<$ kRight $>)" />
          <area href="#" shape="poly" coords="66,281,75,285,86,285,95,281,106,291,100,295,87,300,73,300,58,291,57,289,58,289" alt="Down" onclick="return KeyPress(<$ kDown $>)" />
          <area href="#" shape="poly" coords="51,236,61,245,56,256,57,266,61,277,52,285,47,278,42,264,43,252,49,240" alt="Left" onclick="return KeyPress(<$ kLeft $>)" />
          <area href="#" shape="circle" coords="81,261,17" alt="Ok" onclick="return KeyPress(<$ kOk $>)" title="&amp;lt;Enter&amp;gt;" />
          <area href="#" shape="rect" coords="25,324,52,339" alt="Red" onclick="return KeyPress(<$ kRed $>)" title="&amp;lt;F1&amp;gt;" />
          <area href="#" shape="rect" coords="53,324,81,339" alt="Green" onclick="return KeyPress(<$ kGreen $>)" title="&amp;lt;F2&amp;gt;" />
          <area href="#" shape="rect" coords="83,324,109,339" alt="Yellow" onclick="return KeyPress(<$ kYellow $>)" title="&amp;lt;F3&amp;gt;" />
          <area href="#" shape="rect" coords="110,324,137,339" alt="Blue" onclick="return KeyPress(<$ kBlue $>)" title="&amp;lt;F4&amp;gt;" />
           </map>
      </div>
    </div></div>
  </body>
</html>
<%include>page_exit.eh</%include>

<%def remote_actions>
<form id="remote"><span>
<span class="label bold"><$ tr("Selection") $>: </span>
%  if (IsGrabImageAvailable() ) {
   <input type="radio" name="screenCon" id="screenCon_grab" onchange="changeScreenContent()"/>&nbsp;<label for="screenCon_grab"><$ tr("Snapshot interval") $>:</label> <select name="interval" onchange="ChangeInterval()"></select>
% }
 <input type="radio" name="screenCon" id="screenCon_osd" onchange="changeScreenContent()" />&nbsp;<label for="screenCon_osd">OSD</label>
 <input type="radio" name="screenCon" id="screenCon_none" onchange="changeScreenContent()" />&nbsp;<label for="screenCon_osd"><$ tr("Stop") $></label>
<span class="sep">&nbsp;</span>
% if (channelID.Valid() ) {
<span class="sep">|</span>
 <& pageelems.hls_channel channelId=(channelID) className="icon" &>
 <& pageelems.m3u_playlist_channel channelId=(channelID) className="icon" &>
% }
</span></form>
</%def>
