var nad = nad || {};

nad.fmtCmd = function(data) {
  return 'Main.' + [data.Variable, data.Value].join(data.Operator);
};

nad.send = function(ctrl, req) {
  m.request({method: 'POST', url: '/api/v1/nad', data: req})
    .then(function (data) {
      ctrl.model({message: nad.fmtCmd(req), reply: nad.fmtCmd(data)});
      return data;
    })
    .then(function (data) {
      if (data.Value === 'On' || data.Value === 'Off') {
        var state = ctrl.state();
        state[data.Variable] = data.Value === 'On';
        ctrl.state(state);
      }
    });
};

nad.controller = function() {
  var ctrl = this;
  ctrl.state = m.prop({});
  ctrl.model = m.prop({});
  ctrl.power = function() {
    nad.send(ctrl, {
      'Variable': 'Power',
      'Operator': '=',
      'Value': ctrl.state().Power ? 'Off' : 'On'
    });
  };
  ctrl.mute = function() {
    nad.send(ctrl, {
      'Variable': 'Mute',
      'Operator': '=',
      'Value': ctrl.state().Mute ? 'Off' : 'On'
    });
  };
  ctrl.volumeUp = function() {
    nad.send(ctrl, {
      'Variable': 'Volume',
      'Operator': '+',
    });
  };
  ctrl.volumeDown = function() {
    nad.send(ctrl, {
      'Variable': 'Volume',
      'Operator': '-',
    });
  };
  ctrl.source = function(value) {
    nad.send(ctrl, {
      'Variable': 'Source',
      'Operator': '=',
      'Value': value
    });
  };
  ctrl.amp = function() {
    nad.send(ctrl, {
      'Variable': 'Model',
      'Operator': '?'
    });
  };
};

nad.console = function(ctrl) {
  var text;
  if (Object.keys(ctrl.model()).length === 0) {
    text = ['These go to eleven!'];
  } else {
    text = ['sent:     ' + ctrl.model().message,
            'received: ' + ctrl.model().reply];
  }
  return m('pre.console', text.join('\n'));
};

nad.onoff = function(ctrl, options) {
  var isOn = !!ctrl.state()[options.type];
  return m('button[type=button]', {
    class: 'btn btn-default btn-lg' + (isOn ? ' active' : ''),
    onclick: options.onclick
  }, options.icon);
};

nad.volume = function(ctrl, options) {
  return m('button[type=button]', {
    class: 'btn btn-default btn-lg',
    onclick: options.onclick
  }, options.icon);
};

nad.source = function(ctrl) {
  return m('select.form-control', {
    onchange: m.withAttr('value', ctrl.source)
  }, [
    m('option[value=CD]', 'CD'),
    m('option[value=TUNER]', 'Tuner'),
    m('option[value=VIDEO]', 'Video'),
    m('option[value=DISC/MDC]', 'Disc/MDC'),
    m('option[value=TAPE2]', 'Tape2'),
    m('option[value=AUX]', 'Aux')
  ]);
};

nad.amp = function(ctrl) {
  return m('button[type=button]', {
    class: 'btn btn-default',
    onclick: ctrl.amp
  }, 'Model');
};

nad.view = function(ctrl) {
  return m('div.container', [
    m('h1', 'NAD Remote'),
    m('div.row', [
      m('div.col-md-4', [
        nad.console(ctrl)
      ])
    ]),
    m('div.row', [
      m('div.col-md-2', {class: 'top-spacing'}, [
        nad.onoff(ctrl, {
          onclick: ctrl.power,
          type: 'Power',
          icon: m('span', {class: 'glyphicon glyphicon-off'})
        })
      ]),
      m('div.col-md-2', {class: 'top-spacing'}, [
        nad.onoff(ctrl, {
          onclick: ctrl.mute,
          type: 'Mute',
          icon: m('span', {class: 'glyphicon glyphicon-volume-off'})
        })
      ])
    ]),
    m('div.row', [
      m('div.col-md-2', {class: 'top-spacing'}, [
        nad.volume(ctrl, {
          onclick: ctrl.volumeUp,
          icon: m('span', {class: 'glyphicon glyphicon-volume-up'})
        })
      ]),
      m('div.col-md-2', {class: 'top-spacing'}, [
        nad.volume(ctrl, {
          onclick: ctrl.volumeDown,
          icon: m('span', {class: 'glyphicon glyphicon-volume-down'})
        })
      ])
    ]),
    m('div.row', {class: 'top-spacing'}, [
      m('div.col-md-4', [nad.source(ctrl)])
    ]),
    m('div.row', {class: 'top-spacing'}, [
      m('div.col-md-2', {class: 'col-md-offset-2'}, [nad.amp(ctrl)])
    ])
  ]);
};

m.module(document.getElementById('nad-remote'), nad);

@@ -249,126 +249,39 @@
     
-ctrl.model(%7Bmessage: nad.fmtCmd(req), reply: nad.fmtCmd(data)%7D);%0A      return data;%0A    %7D)%0A    .then(function (data) %7B
+var state = ctrl.model().state;
 %0A   
@@ -338,42 +338,8 @@
 ) %7B%0A
-        var state = ctrl.state();%0A
     
@@ -384,24 +384,30 @@
 === 'On';%0A  
+    %7D%0A
       ctrl.s
@@ -409,29 +409,111 @@
 trl.
-state(state);
+model(%7B%0A        message: nad.fmtCmd(req),%0A        reply: nad.fmtCmd(data),%0A        state: state
 %0A      %7D
 %0A   
@@ -508,24 +508,25 @@
 %0A      %7D
+);
 %0A    %7D)
-;
 %0A%7D;%0A%0Anad
@@ -578,21 +578,21 @@
 %0A  ctrl.
-state
+model
  = m.pro
@@ -598,35 +598,17 @@
 op(%7B
-%7D);%0A  ctrl.model = m.prop(%7B
+state: %7B%7D
 %7D);%0A
@@ -726,23 +726,29 @@
 ': ctrl.
+model().
 state
-()
 .Power ?
@@ -891,23 +891,29 @@
 ': ctrl.
+model().
 state
-()
 .Mute ? 
@@ -1511,13 +1511,12 @@
 gth 
-=== 0
+%3C= 1
 ) %7B%0A
@@ -1773,15 +1773,21 @@
 trl.
+model().
 state
-()
 %5Bopt

Save state in model prop