(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.main = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


var api = require('./api');


module.exports = {
  template: '#admin-general-view-template',
  props: ['config', 'state'],


  data: function () {
    return {
      configRestored: false,
      confirmReset: false,
      configReset: false,
      latest: '',
      autoCheckUpgrade: true
    }
  },


  events: {
    latest_version: function (version) {this.latest = version}
  },


  ready: function () {
    this.autoCheckUpgrade = this.config.admin['auto-check-upgrade']
  },


  methods: {
    backup: function () {
      document.getElementById('download-target').src = '/api/config/download';
    },


    restore: function (e) {
      var files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;

      var fr = new FileReader();
      fr.onload = function (e) {
        var config;

        try {
          config = JSON.parse(e.target.result);
        } catch (ex) {
          alert("Invalid config file");
          return;
        }

        api.put('config/save', config).done(function (data) {
          this.$dispatch('update');
          this.configRestored = true;

        }.bind(this)).fail(function (error) {
          alert('Restore failed: ' + error);
        })
      }.bind(this);

      fr.readAsText(files[0]);
    },


    reset: function () {
      this.confirmReset = false;
      api.put('config/reset').done(function () {
        this.$dispatch('update');
        this.configReset = true;

      }.bind(this)).fail(function (error) {
        alert('Reset failed: ' + error);
      });
    },


    check: function () {this.$dispatch('check')},
    upgrade: function () {this.$dispatch('upgrade')},


    upload: function (e) {
      var files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;
      this.$dispatch('upload', files[0]);
    },


    change_auto_check_upgrade: function () {
      this.config.admin['auto-check-upgrade'] = this.autoCheckUpgrade;
      this.$dispatch('config-changed');
    }
  }
}

},{"./api":3}],2:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


var api = require('./api');


module.exports = {
  template: '#admin-network-view-template',
  props: ['config', 'state'],


  data: function () {
    return {
      hostnameSet: false,
      usernameSet: false,
      passwordSet: false,
      redirectTimeout: 0,
      hostname: '',
      username: '',
      current: '',
      password: '',
      password2: '',
      wifi_mode: 'client',
      wifi_ssid: '',
      wifi_ch: undefined,
      wifi_pass: '',
      wifiConfirm: false,
      rebooting: false
    }
  },


  ready: function () {
    api.get('hostname').done(function (hostname) {
      this.hostname = hostname;
    }.bind(this));

    api.get('remote/username').done(function (username) {
      this.username = username;
    }.bind(this));

    api.get('wifi').done(function (config) {
      this.wifi_mode = config.mode;
      this.wifi_ssid = config.ssid;
      this.wifi_ch = config.channel;
    }.bind(this));
  },


  methods: {
    redirect: function (hostname) {
      if (0 < this.redirectTimeout) {
        this.redirectTimeout -= 1;
        setTimeout(function () {this.redirect(hostname)}.bind(this), 1000);

      } else location.hostname = hostname;
    },


    set_hostname: function () {
      api.put('hostname', {hostname: this.hostname}).done(function () {
        this.redirectTimeout = 45;
        this.hostnameSet = true;

        api.put('reboot').always(function () {
          var hostname = this.hostname;
          if (String(location.hostname).endsWith('.local'))
            hostname += '.local'
          this.$dispatch('hostname-changed', hostname);
          this.redirect(hostname);
        }.bind(this));

      }.bind(this)).fail(function (error) {
        alert('Set hostname failed: ' + JSON.stringify(error));
      })
    },


    set_username: function () {
      api.put('remote/username', {username: this.username}).done(function () {
        this.usernameSet = true;
      }.bind(this)).fail(function (error) {
        alert('Set username failed: ' + JSON.stringify(error));
      })
    },


    set_password: function () {
      if (this.password != this.password2) {
        alert('Passwords to not match');
        return;
      }

      if (this.password.length < 6) {
        alert('Password too short');
        return;
      }

      api.put('remote/password', {
        current: this.current,
        password: this.password
      }).done(function () {
        this.passwordSet = true;
      }.bind(this)).fail(function (error) {
        alert('Set password failed: ' + JSON.stringify(error));
      })
    },


    config_wifi: function () {
      this.wifiConfirm = false;
      this.rebooting = true;

      var config = {
        mode: this.wifi_mode,
        channel: this.wifi_ch,
        ssid: this.wifi_ssid,
        pass: this.wifi_pass
      }

      api.put('wifi', config).fail(function (error) {
        alert('Failed to configure WiFi: ' + JSON.stringify(error));
      })
    }
  }
}

},{"./api":3}],3:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


function api_cb(method, url, data, config) {
  config = $.extend({
    type: method,
    url: '/api/' + url,
    dataType: 'json',
    cache: false
  }, config);

  if (typeof data == 'object') {
    config.data = JSON.stringify(data);
    config.contentType = 'application/json; charset=utf-8';
  }

  var d = $.Deferred();

  $.ajax(config).success(function (data, status, xhr) {
    d.resolve(data, status, xhr);

  }).error(function (xhr, status, error) {
    var text = xhr.responseText;
    try {text = $.parseJSON(xhr.responseText)} catch(e) {}
    d.reject(text, xhr, status, error);
    console.debug('API Error: ' + url + ': ' + xhr.responseText);
  })

  return d.promise();
}


module.exports = {
  get: function (url, config) {
    return api_cb('GET', url, undefined, config);
  },


  put: function(url, data, config) {
    return api_cb('PUT', url, data, config);
  },


  post: function(url, data, config) {
    return api_cb('POST', url, data, config);
  },


  upload: function(url, data, config) {
    config = $.extend({
      processData: false,
      contentType: false,
      cache: false,
      data: data
    }, config);

    return api_cb('PUT', url, undefined, config);
  },


  'delete': function (url, config) {
    return api_cb('DELETE', url, undefined, config);
  }
}

},{}],4:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'

var api = require('./api');
var Sock = require('./sock');


function compare_versions(a, b) {
    var reStripTrailingZeros = /(\.0+)+$/;
    var segsA = a.replace(reStripTrailingZeros, '').split('.');
    var segsB = b.replace(reStripTrailingZeros, '').split('.');
    var l = Math.min(segsA.length, segsB.length);

    for (var i = 0; i < l; i++) {
      var diff = parseInt(segsA[i], 10) - parseInt(segsB[i], 10);
      if (diff) return diff;
    }

    return segsA.length - segsB.length;
}


function is_object(o) {return o !== null && typeof o == 'object'}


function update_object(dst, src, remove) {
  var props, index, key, value;

  if (remove) {
    props = Object.getOwnPropertyNames(dst);

    for (index in props) {
      key = props[index];
      if (!src.hasOwnProperty(key))
        Vue.delete(dst, key);
    }
  }

  props = Object.getOwnPropertyNames(src);
  for (index in props) {
    key = props[index];
    value = src[key];

    if (is_object(value) && dst.hasOwnProperty(key) && is_object(dst[key]))
      update_object(dst[key], value, remove);

    else Vue.set(dst, key, value);
  }
}


module.exports = new Vue({
  el: 'body',


  data: function () {
    return {
      status: 'connecting',
      currentView: 'loading',
      index: -1,
      modified: false,
      template: {motors: {template: {}}},
      config: {
        settings: {units: 'METRIC'},
        motors: [{}, {}, {}, {}],
        version: '<loading>'
      },
      state: {},
      messages: [],
      errorTimeout: 30,
      errorTimeoutStart: 0,
      errorShow: false,
      errorMessage: '',
      reloadOnConnect: false,
      confirmUpgrade: false,
      confirmUpload: false,
      firmwareUpgrading: false,
      checkedUpgrade: false,
      firmwareName: '',
      latestVersion: '',
      password: '',
      showMessages: false
    }
  },


  components: {
    'estop': {template: '#estop-template'},
    'loading-view': {template: '<h1>Loading...</h1>'},
    'control-view': require('./control-view'),
    'settings-view': require('./settings-view'),
    'motor-view': require('./motor-view'),
    'tool-view': require('./tool-view'),
    'io-view': require('./io-view'),
    'admin-general-view': require('./admin-general-view'),
    'admin-network-view': require('./admin-network-view'),
    'help-view': {template: '#help-view-template'},
    'cheat-sheet-view': {
      template: '#cheat-sheet-view-template',
      data: function () {return {showUnimplemented: false}}
    }
  },


  events: {
    'config-changed': function () {this.modified = true;},
    'hostname-changed': function (hostname) {this.hostname = hostname},


    send: function (msg) {
      if (this.status == 'connected') {
        console.debug('>', msg);
        this.sock.send(msg);
      }
    },


    connected: function () {
      if (this.reloadOnConnect) {
        if (typeof this.hostname != 'undefined')
          location.hostname = this.hostname;
        location.reload(true);
      } else this.update();
    },


    disconnected: function () {this.reloadOnConnect = true},
    update: function () {this.update()},


    check: function () {
      this.latestVersion = '';

      $.ajax({
        type: 'GET',
        url: 'https://buildbotics.com/bbctrl/latest.txt',
        data: {hid: this.state.hid},
        cache: false

      }).done(function (data) {
        this.latestVersion = data;
        this.$broadcast('latest_version', data);
      }.bind(this))
    },


    upgrade: function () {
      this.password = '';
      this.confirmUpgrade = true;
    },


    upload: function (firmware) {
      this.firmware = firmware;
      this.firmwareName = firmware.name;
      this.password = '';
      this.confirmUpload = true;
    },


    error: function (msg) {
      // Honor user error blocking
      if (Date.now() - this.errorTimeoutStart < this.errorTimeout * 1000)
        return;

      // Wait at least 1 sec to pop up repeated errors
      if (1 < msg.repeat && Date.now() - msg.ts < 1000) return;

      // Popup error dialog
      this.errorShow = true;
      this.errorMessage = msg.msg;
    }
  },


  ready: function () {
    $(window).on('hashchange', this.parse_hash);
    this.connect();
  },


  methods: {
    metric: function () {return this.config.settings.units != 'IMPERIAL'},


    block_error_dialog: function () {
      this.errorTimeoutStart = Date.now();
      this.errorShow = false;
    },


    estop: function () {
      if (this.state.xx == 'ESTOPPED') api.put('clear');
      else api.put('estop');
    },


    upgrade_confirmed: function () {
      this.confirmUpgrade = false;

      api.put('upgrade', {password: this.password}).done(function () {
        this.firmwareUpgrading = true;

      }.bind(this)).fail(function () {
        alert('Invalid password');
      }.bind(this))
    },


    upload_confirmed: function () {
      this.confirmUpload = false;

      var form = new FormData();
      form.append('firmware', this.firmware);
      if (this.password) form.append('password', this.password);

      $.ajax({
        url: '/api/firmware/update',
        type: 'PUT',
        data: form,
        cache: false,
        contentType: false,
        processData: false

      }).success(function () {
        this.firmwareUpgrading = true;

      }.bind(this)).error(function () {
        alert('Invalid password or bad firmware');
      }.bind(this))
    },


    show_upgrade: function () {
      if (!this.latestVersion) return false;
      return compare_versions(this.config.version, this.latestVersion) < 0;
    },


    update: function () {
      $.ajax({type: 'GET', url: '/config-template.json', cache: false})
        .success(function (data, status, xhr) {
          this.template = data;

          api.get('config/load').done(function (config) {
            update_object(this.config, config, true);
            this.parse_hash();

            if (!this.checkedUpgrade) {
              this.checkedUpgrade = true;

              var check = this.config.admin['auto-check-upgrade'];
              if (typeof check == 'undefined' || check)
                this.$emit('check');
            }
          }.bind(this))
        }.bind(this))
    },


    connect: function () {
      this.sock = new Sock('//' + window.location.host + '/sockjs');

      this.sock.onmessage = function (e) {
        if (typeof e.data != 'object') return;

        if ('log' in e.data) {
          this.$broadcast('log', e.data.log);
          delete e.data.log;
        }

        if ('message' in e.data) {
          this.add_message(e.data.message);
          delete e.data.message;
        }

        update_object(this.state, e.data, false);
        this.$broadcast('update');

      }.bind(this)

      this.sock.onopen = function (e) {
        this.status = 'connected';
        this.$emit(this.status);
        this.$broadcast(this.status);
      }.bind(this)

      this.sock.onclose = function (e) {
        this.status = 'disconnected';
        this.$emit(this.status);
        this.$broadcast(this.status);
      }.bind(this)
    },


    parse_hash: function () {
      var hash = location.hash.substr(1);

      if (!hash.trim().length) {
        location.hash = 'control';
        return;
      }

      var parts = hash.split(':');

      if (parts.length == 2) this.index = parts[1];

      this.currentView = parts[0];
    },


    save: function () {
      api.put('config/save', this.config).done(function (data) {
        this.modified = false;
      }.bind(this)).fail(function (error) {
        alert('Save failed: ' + error);
      });
    },


    add_message: function (msg) {
      this.messages.unshift(msg);
      this.showMessages = true;
    },


    close_messages: function (action) {
      this.showMessages = false;
      this.messages.splice(0, this.messages.length);

      if (action == 'stop') api.put('stop');
      if (action == 'continue') api.put('unpause');
    }
  }
})

},{"./admin-general-view":1,"./admin-network-view":2,"./api":3,"./control-view":7,"./io-view":10,"./motor-view":15,"./settings-view":16,"./sock":17,"./tool-view":19}],5:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  template: '#axis-control-template',
  props: ['axes', 'colors', 'enabled', 'adjust'],


  methods: {
    jog: function (axis, power) {
      this.$dispatch('jog', this.axes[axis], power * this.adjust / 100.0)
    },


    release: function (axis) {this.$dispatch('jog', this.axes[axis], 0)}
  }
}

},{}],6:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


function _msg_equal(a, b) {
  return a.level == b.level && a.location == b.location && a.code == b.code &&
    a.msg == b.msg;
}


// Shared among all instances
var messages = [];


module.exports = {
  template: '#console-template',


  data: function () {
    return {messages: messages}
  },


  events: {
    log: function (msg) {
      // There may be multiple instances of this module so ignore messages
      // that have already been processed.
      if (msg.logged) return;
      msg.logged = true;

      // Make sure we have a message level
      msg.level = msg.level || 'info';

      // Add to message log and count and collapse repeats
      var repeat = messages.length && _msg_equal(msg, messages[0]);
      if (repeat) messages[0].repeat++;
      else {
        msg.repeat = 1;
        messages.unshift(msg);
        while (256 < messages.length) messages.pop();
      }
      msg.ts = Date.now();

      // Write message to browser console for debugging
      var text = JSON.stringify(msg);
      if (msg.level == 'error' || msg.level == 'critical') console.error(text);
      else if (msg.level == 'warning') console.warn(text);
      else if (msg.level == 'debug' && console.debug) console.debug(text);
      else console.log(text);

      // Event on errors
      if (msg.level == 'error' || msg.level == 'critical')
        this.$dispatch('error', msg);
    }
  },


  methods: {
    clear: function () {messages.splice(0, messages.length);},
  }
}

},{}],7:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'

var api = require('./api');


function _is_array(x) {
  return Object.prototype.toString.call(x) === '[object Array]';
}


function escapeHTML(s) {
  var entityMap = {'&': '&amp;', '<': '&lt;', '>': '&gt;'};
  return String(s).replace(/[&<>]/g, function (s) {return entityMap[s];});
}


module.exports = {
  template: '#control-view-template',
  props: ['config', 'template', 'state'],


  data: function () {
    return {
      mach_units: 'METRIC',
      mdi: '',
      files: [],
      axes: 'xyzabc',
      history: [],
      speed_override: 1,
      feed_override: 1,
      manual_home: {x: false, y: false, z: false, a: false, b: false, c: false},
      position_msg:
      {x: false, y: false, z: false, a: false, b: false, c: false},
      axis_position: 0,
      jog_adjust: 100,
      video_url: '',
      deleteGCode: false
    }
  },


  components: {
    'axis-control': require('./axis-control'),
    'gcode-viewer': require('./gcode-viewer')
  },


  watch: {
    'state.imperial': {
      handler: function (imperial) {
        this.mach_units = imperial ? 'IMPERIAL' : 'METRIC';
      },
      immediate: true
    },


    mach_units: function (units) {
      if ((units == 'METRIC') != this.metric)
        this.send(units == 'METRIC' ? 'G21' : 'G20');
    },


    'state.line': function () {
      if (this.mach_state != 'HOMING')
        this.$broadcast('gcode-line', this.state.line);
    },


    'state.selected': function () {this.load()}
  },


  computed: {
    metric: function () {return !this.state.imperial},


    mach_state: function () {
      var cycle = this.state.cycle;
      var state = this.state.xx;

      if (typeof cycle != 'undefined' && state != 'ESTOPPED' &&
          (cycle == 'jogging' || cycle == 'homing'))
        return cycle.toUpperCase();
      return state || ''
    },


    is_running: function () {
      return this.mach_state == 'RUNNING' || this.mach_state == 'HOMING';
    },


    is_stopping: function () {return this.mach_state == 'STOPPING'},
    is_holding: function () {return this.mach_state == 'HOLDING'},
    is_ready: function () {return this.mach_state == 'READY'},


    can_mdi: function () {
      return this.state.cycle == 'idle' || this.state.cycle == 'mdi';
    },


    reason: function () {
      if (this.mach_state == 'ESTOPPED') return this.state.er;
      if (this.mach_state == 'HOLDING') return this.state.pr;
      return '';
    },


    highlight_reason: function () {return this.reason != ''}
  },


  events: {
    jog: function (axis, power) {
      var data = {};
      data[axis] = power;
      api.put('jog', data);
    },

    connected: function () {this.update()}
  },


  ready: function () {
    this.update();
    this.load();
  },


  methods: {
    send: function (msg) {this.$dispatch('send', msg)},


    get_axis_motor_id: function (axis) {
      axis = axis.toLowerCase();

      for (var i = 0; i < this.config.motors.length; i++) {
        var motor = this.config.motors[i];
        if (motor.axis.toLowerCase() == axis) return i;
      }

      return -1;
    },


    get_axis_motor: function (axis) {
      var motor = this.get_axis_motor_id(axis);
      if (motor != -1) return this.config.motors[motor];
    },


    get_axis_motor_param: function (axis, name) {
      var motor = this.get_axis_motor(axis);
      if (typeof motor != 'undefined') return motor[name];
    },


    enabled: function (axis) {
      var pm = this.get_axis_motor_param(axis, 'power-mode')
      return typeof pm != 'undefined' && pm != 'disabled';
    },


    is_homed: function (axis) {
      if (typeof axis == 'undefined') {
        var enabled = false;
        var axes = 'xyzabc';

        for (var i in axes) {
          if (this.enabled(axes.charAt(i))) {
            if (!this.is_homed(axes.charAt(i))) return false;
            else enabled = true;
          }
        }

        return enabled;

      } else {
        var motor = this.get_axis_motor_id(axis);
        return motor != -1 && this.state[motor + 'homed'];
      }
    },


    update: function () {
      // Update file list
      api.get('file').done(function (files) {
        this.files = files;
        this.load();
      }.bind(this))
    },


    load: function () {
      var file = this.state.selected;
      if (typeof file != 'undefined') this.$broadcast('gcode-load', file);
      this.$broadcast('gcode-line', this.state.line);
    },


    submit_mdi: function () {
      this.send(this.mdi);
      if (!this.history.length || this.history[0] != this.mdi)
        this.history.unshift(this.mdi);
      this.mdi = '';
    },


    mdi_start_pause: function () {
      if (this.state.xx == 'RUNNING') this.pause();

      else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING')
        this.unpause();

      else this.submit_mdi();
    },


    load_history: function (index) {this.mdi = this.history[index];},


    open: function (e) {
      $('.gcode-file-input').click();
    },


    upload: function (e) {
      var files = e.target.files || e.dataTransfer.files;
      if (!files.length) return;

      var file = files[0];
      var fd = new FormData();

      fd.append('gcode', file);

      api.upload('file', fd)
        .done(function () {
          this.$broadcast('gcode-reload', file.name);
          this.update();
        }.bind(this));
    },


    deleteCurrent: function () {
      if (this.state.selected)
        api.delete('file/' + this.state.selected).done(this.update);
      this.deleteGCode = false;
    },


    deleteAll: function () {
      api.delete('file').done(this.update);
      this.deleteGCode = false;
    },


    home: function (axis) {
      if (typeof axis == 'undefined') api.put('home');

      else {
        if (this.get_axis_motor_param(axis, 'homing-mode') != 'manual')
          api.put('home/' + axis);
        else this.manual_home[axis] = true;
      }
    },


    set_home: function (axis, position) {
      this.manual_home[axis] = false;
      api.put('home/' + axis + '/set', {position: parseFloat(position)});
    },


    unhome: function (axis) {
      this.position_msg[axis] = false;
      api.put('home/' + axis + '/clear');
    },


    show_set_position: function (axis) {
      this.axis_position = 0;
      this.position_msg[axis] = true;
    },


    get_offset: function (axis) {return this.state['offset_' + axis] || 0},


    set_position: function (axis, position) {
      this.position_msg[axis] = false;
      api.put('position/' + axis, {'position': parseFloat(position)});
    },


    zero: function (axis) {
      if (typeof axis == 'undefined') {
        var axes = 'xyzabc';
        for (var i in axes)
          if (this.enabled(axes.charAt(i)))
            this.zero(axes.charAt(i));

      } else this.set_position(axis, 0);
    },


    start_pause: function () {
      if (this.state.xx == 'RUNNING') this.pause();

      else if (this.state.xx == 'STOPPING' || this.state.xx == 'HOLDING')
        this.unpause();

      else this.start();
    },


    start: function () {api.put('start')},
    pause: function () {api.put('pause')},
    unpause: function () {api.put('unpause')},
    optional_pause: function () {api.put('pause/optional')},
    stop: function () {api.put('stop')},
    step: function () {api.put('step')},


    override_feed: function () {api.put('override/feed/' + this.feed_override)},


    override_speed: function () {
      api.put('override/speed/' + this.speed_override)
    },


    current: function (axis, value) {
      var x = value / 32.0;
      if (this.state[axis + 'pl'] == x) return;

      var data = {};
      data[axis + 'pl'] = x;
      this.send(JSON.stringify(data));
    },


    load_video: function () {
      this.video_url = '//' + document.location.hostname + ':8000/stream/0?=' +
        Math.random();
    },


    reload_video: function () {
      if (typeof this.lastVideoReset != 'undefined' &&
          Date.now() - this.lastVideoReset < 15000) return;

      this.lastVideoReset = Date.now();
      api.put('video/reload');
      setTimeout(this.load_video, 4000);
    }
  }
}

},{"./api":3,"./axis-control":5,"./gcode-viewer":8}],8:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'

var api = require('./api');

var max_lines = 1000;
var page_size = Math.round(max_lines / 10);


module.exports = {
  template: '#gcode-viewer-template',


  data: function () {
    return {
      empty: true,
      file: '',
      line: -1,
      scrolling: false
    }
  },


  events: {
    'gcode-load': function (file) {this.load(file)},
    'gcode-clear': function () {this.clear()},
    'gcode-reload': function (file) {this.reload(file)},
    'gcode-line': function (line) {this.update_line(line)}
  },


  ready: function () {
    this.clusterize = new Clusterize({
      rows: [],
      scrollElem: $(this.$el).find('.clusterize-scroll')[0],
      contentElem: $(this.$el).find('.clusterize-content')[0],
      callbacks: {clusterChanged: this.highlight}
    });
  },


  attached: function () {
    if (typeof this.clusterize != 'undefined')
      this.clusterize.refresh(true);
  },


  methods: {
    load: function (file) {
      if (file == this.file) return;
      this.clear();
      this.file = file;

      api.get('file/' + file)
        .done(function (data) {
          var lines = data.trimRight().split(/\r?\n/);

          for (var i = 0; i < lines.length; i++) {
            lines[i] = '<li class="line-' + (i + 1) + '">' +
              '<span class="gcode-line">' + (i + 1) + '</span>' +
              lines[i] + '</li>';
          }

          this.clusterize.update(lines);
          this.empty = false;

          Vue.nextTick(this.update_line);
        }.bind(this));
    },


    clear: function () {
      this.empty = true;
      this.file = '';
      this.line = -1;
      this.clusterize.clear();
    },


    reload: function (file) {
      if (file != this.file) return;
      this.clear();
      this.load(file);
    },


    highlight: function () {
      var e = $(this.$el).find('.highlight');
      if (e.length) e.removeClass('highlight');

      e = $(this.$el).find('.line-' + this.line);
      if (e.length) e.addClass('highlight');
    },


    update_line: function(line) {
      if (typeof line != 'undefined') {
        if (this.line == line) return;
        this.line = line;

      } else line = this.line;

      var totalLines = this.clusterize.getRowsAmount();

      if (line <= 0) line = 1;
      if (totalLines < line) line = totalLines;

      var e = $(this.$el).find('.clusterize-scroll');

      var lineHeight = e[0].scrollHeight / totalLines;
      var linesPerPage = Math.floor(e[0].clientHeight / lineHeight);
      var current = e[0].scrollTop / lineHeight;
      var target = line - 1 - Math.floor(linesPerPage / 2);

      // Update scroll position
      if (!this.scrolling) {
        if (target < current - 20 || current + 20 < target)
          e[0].scrollTop = target * lineHeight;

        else {
          this.scrolling = true;
          e.animate({scrollTop: target * lineHeight}, {
            complete: function () {this.scrolling = false}.bind(this)
          })
        }
      }

      Vue.nextTick(this.highlight);
    }
  }
}

},{"./api":3}],9:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'

var modbus = require('./modbus.js');


module.exports = {
  template: '#indicators-template',
  props: ['state'],


  computed: {
    modbus_status: function () {return modbus.status_to_string(this.state.mx)}
  },


  methods: {
    is_motor_enabled: function (motor) {
      return typeof this.state[motor + 'pm'] != 'undefined' &&
        this.state[motor + 'pm'];
    },


    get_min_pin: function (motor) {
      switch (motor) {
      case 0: return 3;
      case 1: return 5;
      case 2: return 9;
      case 3: return 11;
      }
    },


    get_max_pin: function (motor) {
      switch (motor) {
      case 0: return 4;
      case 1: return 8;
      case 2: return 10;
      case 3: return 12;
      }
    },


    get_class: function (code) {
      if (typeof this.state[code] != 'undefined') {
        var state = this.state[code];

        if (state == 0 || state === false) return 'logic-lo fa-circle';
        if (state == 1 || state === true) return 'logic-hi fa-circle';
        if (state == 2) return 'logic-tri fa-circle-o';
      }

      return 'fa-exclamation-triangle warn';
    }
  }
}

},{"./modbus.js":14}],10:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  template: '#io-view-template',
  props: ['config', 'template'],


  events: {
    'input-changed': function() {
      this.$dispatch('config-changed');
      return false;
    }
  }
}

},{}],11:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict';


$(function() {
  // Vue debugging
  Vue.config.debug = true;
  //Vue.util.warn = function (msg) {console.debug('[Vue warn]: ' + msg)}

  // Register global components
  Vue.component('templated-input', require('./templated-input'));
  Vue.component('message', require('./message'));
  Vue.component('indicators', require('./indicators'));
  Vue.component('console', require('./console'));
  Vue.component('unit-value', require('./unit-value'));

  Vue.filter('percent', function (value, precision) {
    if (typeof precision == 'undefined') precision = 2;
    return (value * 100.0).toFixed(precision) + '%';
  });

  Vue.filter('fixed', function (value, precision) {
    if (typeof value == 'undefined') return '';
    return parseFloat(value).toFixed(precision)
  });

  Vue.filter('upper', function (value) {
    if (typeof value == 'undefined') return '';
    return value.toUpperCase()
  });

  // Vue app
  require('./app');
});

},{"./app":4,"./console":6,"./indicators":9,"./message":12,"./templated-input":18,"./unit-value":20}],12:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  template: '#message-template',

  props: {
    show: {
      type: Boolean,
      required: true,
      twoWay: true
    }
  }
}

},{}],13:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  replace: true,
  template: '#modbus-reg-view-template',
  props: ['index', 'model', 'template', 'enable'],


  computed: {
    has_user_value: function () {
      var type = this.model['reg-type'];
      return type.indexOf('write') != -1 || type.indexOf('fixed') != -1;
    }
  },


  methods: {
    change: function () {this.$dispatch('input-changed')}
  }
}

},{}],14:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


// Must match modbus.c
var exports = {
  DISCONNECTED: 0,
  OK:           1,
  CRC:          2,
  INVALID:      3,
  TIMEDOUT:     4
};


exports.status_to_string =
  function (status) {
    if (status == exports.OK)       return 'Ok';
    if (status == exports.CRC)      return 'CRC error';
    if (status == exports.INVALID)  return 'Invalid response';
    if (status == exports.TIMEDOUT) return 'Timedout';
    return 'Disconnected';
  }


module.exports = exports;

},{}],15:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  template: '#motor-view-template',
  props: ['index', 'config', 'template'],


  computed: {
    metric: function () {return this.$root.metric()},


    is_slave: function () {
      for (var i = 0; i < this.index; i++)
        if (this.motor.axis == this.config.motors[i].axis)
          return true;

      return false;
    },


    motor: function () {return this.config.motors[this.index]},


    rpm: function () {
      return 1000 * this.motor['max-velocity'] / this.motor['travel-per-rev'];
    },


    gForce: function () {return this.motor['max-accel'] * 0.0283254504},
    gForcePerMin: function () {return this.motor['max-jerk'] * 0.0283254504},
    stepsPerRev: function () {return 360 / this.motor['step-angle']},


    umPerStep: function () {
      return this.motor['travel-per-rev'] * this.motor['step-angle'] / 0.36
    },


    milPerStep: function () {return this.umPerStep / 25.4}
  },


  events: {
    'input-changed': function() {
      this.$dispatch('config-changed');
      return false;
    }
  }
}

},{}],16:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  template: '#settings-view-template',
  props: ['config', 'template'],


  events: {
    'input-changed': function() {
      this.$dispatch('config-changed');
      return false;
    }
  }
}

},{}],17:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


var Sock = function (url, retry, timeout) {
  if (!(this instanceof Sock)) return new Sock(url, retry);

  if (typeof retry == 'undefined') retry = 2000;
  if (typeof timeout == 'undefined') timeout = 8000;

  this.url = url;
  this.retry = retry;
  this.timeout = timeout;

  this.connect();
}


Sock.prototype.onmessage = function () {}
Sock.prototype.onopen = function () {}
Sock.prototype.onclose = function () {}


Sock.prototype.connect = function () {
  console.debug('connecting to', this.url);
  this.close();

  this._sock = new SockJS(this.url);

  this._sock.onmessage = function (e) {
    console.debug('msg:', e.data);
    this._set_timeout();
    this.onmessage(e);
  }.bind(this);


  this._sock.onopen = function () {
    console.debug('connected');
    this._set_timeout();
    this.onopen();
  }.bind(this);


  this._sock.onclose = function () {
    console.debug('disconnected');
    this._cancel_timeout();

    this.onclose();
    if (typeof this._sock != 'undefined')
      setTimeout(this.connect.bind(this), this.retry);
  }.bind(this);
}


Sock.prototype._set_timeout = function () {
  this._cancel_timeout();
  this._timeout = setTimeout(this._timedout.bind(this), this.timeout);
}


Sock.prototype._timedout = function () {
  console.debug('connection timedout');
  this._timeout = undefined;
  this._sock.close();
}


Sock.prototype._cancel_timeout = function () {
  clearTimeout(this._timeout);
  this._timeout = undefined;
}


Sock.prototype.close = function () {
  if (typeof this._sock != 'undefined') {
    var sock = this._sock;
    this._sock = undefined;
    sock.close();
  }
}


Sock.prototype.send = function (msg) {
  this._sock.send(msg);
}


module.exports = Sock

},{}],18:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  replace: true,
  template: '#templated-input-template',
  props: ['name', 'model', 'template'],


  data: function () {return {view: ''}},


  computed: {
    metric: function () {return this.$root.metric()},


    units: function () {
      return (this.metric || !this.template.iunit) ?
        this.template.unit : this.template.iunit;
    }
  },


  watch: {
    metric: function () {this.set_view()},
    model: function () {this.set_view()}
  },


  ready: function () {this.set_view()},


  methods: {
    set_view: function () {
      if (this.template.scale && !this.metric)
        this.view = (this.model / this.template.scale).toFixed(2);
      else this.view = this.model;
    },


    change: function () {
      if (this.template.scale && !this.metric)
        this.model = 1 * (this.view * this.template.scale).toFixed(3);
      else this.model = this.view;

      this.$dispatch('input-changed');
    }
  }
}

},{}],19:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict';

var api = require('./api');
var modbus = require('./modbus.js');


module.exports = {
  template: '#tool-view-template',
  props: ['config', 'template', 'state'],


  data: function () {
    return {
      address: 0,
      value: 0
    }
  },


  components: {'modbus-reg': require('./modbus-reg.js')},


  watch: {
    'state.mr': function () {this.value = this.state.mr}
  },


  events: {
    'input-changed': function() {
      this.$dispatch('config-changed');
      return false;
    }
  },


  ready: function () {this.value = this.state.mr},


  computed: {
    regs_tmpl: function () {return this.template['modbus-spindle'].regs},
    tool_type: function () {return this.config.tool['tool-type'].toUpperCase()},


    is_modbus: function () {
      return this.tool_type != 'DISABLED' && this.tool_type != 'PWM SPINDLE'
    },


    modbus_status: function () {return modbus.status_to_string(this.state.mx)}
  },


  methods: {
    get_reg_type: function (reg) {
      return this.regs_tmpl.template['reg-type'].values[this.state[reg + 'vt']]
    },


    get_reg_addr: function (reg) {return this.state[reg + 'va']},
    get_reg_value: function (reg) {return this.state[reg + 'vv']},


    get_reg_fails: function (reg) {
      var fails = this.state[reg + 'vr']
      return fails == 255 ? 'Max' : fails;
    },


    read: function (e) {
      e.preventDefault();
      api.put('modbus/read', {address: this.address});
    },


    write: function (e) {
      e.preventDefault();
      api.put('modbus/write', {address: this.address, value: this.value});
    },


    customize: function (e) {
      e.preventDefault();
      this.config.tool['tool-type'] = 'Custom Modbus VFD';

      var regs = this.config['modbus-spindle'].regs;
      for (var i = 0; i < regs.length; i++) {
        var reg = this.regs_tmpl.index[i];
        regs[i]['reg-type']  = this.get_reg_type(reg);
        regs[i]['reg-addr']  = this.get_reg_addr(reg);
        regs[i]['reg-value'] = this.get_reg_value(reg);
      }

      this.$dispatch('config-changed');
    },


    clear: function (e) {
      e.preventDefault();
      this.config.tool['tool-type'] = 'Custom Modbus VFD';

      var regs = this.config['modbus-spindle'].regs;
      for (var i = 0; i < regs.length; i++) {
        regs[i]['reg-type']  = 'disabled';
        regs[i]['reg-addr']  = 0;
        regs[i]['reg-value'] = 0;
      }

      this.$dispatch('config-changed');
    },


    reset_failures: function (e) {
      e.preventDefault();
      var regs = this.config['modbus-spindle'].regs;
      for (var reg = 0; reg < regs.length; reg++)
        this.$dispatch('send', '\$' + reg + 'vr=0');
    }
  }
}

},{"./api":3,"./modbus-reg.js":13,"./modbus.js":14}],20:[function(require,module,exports){
/******************************************************************************\

                 This file is part of the Buildbotics firmware.

                   Copyright (c) 2015 - 2018, Buildbotics LLC
                              All rights reserved.

      This file ("the software") is free software: you can redistribute it
      and/or modify it under the terms of the GNU General Public License,
       version 2 as published by the Free Software Foundation. You should
       have received a copy of the GNU General Public License, version 2
      along with the software. If not, see <http://www.gnu.org/licenses/>.

      The software is distributed in the hope that it will be useful, but
           WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
                 License along with the software.  If not, see
                        <http://www.gnu.org/licenses/>.

                 For information regarding this software email:
                   "Joseph Coffland" <joseph@buildbotics.com>

\******************************************************************************/

'use strict'


module.exports = {
  replace: true,
  template: '{{text}}<span class="unit">{{metric ? unit : iunit}}</span>',
  props: ['value', 'precision', 'unit', 'iunit', 'scale'],


  computed: {
    metric: function () {return !this.$root.state.imperial},


    text: function () {
      var value = this.value;
      if (typeof value == 'undefined') return '';

      if (!this.metric) value /= this.scale;

      return (1 * value.toFixed(this.precision)).toLocaleString();
    }
  },


  ready: function () {
    if (typeof this.precision == 'undefined') this.precision = 0;
    if (typeof this.unit == 'undefined') this.unit = 'mm';
    if (typeof this.iunit == 'undefined') this.iunit = 'in';
    if (typeof this.scale == 'undefined') this.scale = 25.4;
  }
}

},{}]},{},[11])(11)
});