text: var base58 = require('../lib/Base58').base58Check;
  var bech32 = require('bech32');
  var networks = require('../networks');
  
  // Constructor.  Takes the following forms:
  //   new EncodedData(<base58_address_string>)
  //   new EncodedData(<Bech32_address_string>)
  //   new EncodedData(<binary_buffer>)
  //   new EncodedData(<data>, <encoding>)
  //   new EncodedData(<version>, <20-byte-hash>)
  function EncodedData(data, encoding) {
    this.data = data;
    if (!encoding && (typeof data == 'string')) {
      if (data.indexOf(networks['livenet'].bech32Prefix) === 0 || data.indexOf(networks['testnet'].bech32Prefix) === 0){
        encoding = 'bech32';
      }else{
        encoding = 'base58';
      }
      this.converters = this.encodings[encoding].converters;
      this._encoding = this.encodings[encoding]._encoding;
    } else {
      if (typeof this.encodings[encoding] === 'undefined')
        encoding = 'binary';
      this.converters = this.encodings[encoding].converters;
      this._encoding = this.encodings[encoding]._encoding;
    }
  };
  
  // get or set the encoding used (transforms data)
  EncodedData.prototype.encoding = function(encoding) {
    if (encoding && (encoding != this._encoding)) {
      this.data = this.as(encoding);
      this.converters = this.encodings[encoding].converters;
      this._encoding = this.encodings[encoding]._encoding;
    }
    return this._encoding;
  };
  
  // answer a new instance having the given encoding
  EncodedData.prototype.withEncoding = function(encoding) {
    return new EncodedData(this.as(encoding), encoding);
  };
  
  // answer the data in the given encoding
  EncodedData.prototype.as = function(encoding) {
    if (!encodings[encoding]) throw new Error('invalid encoding: '+encoding);
    return this.converters[encoding].call(this);
  };
  
  // validate that we can convert to binary
  EncodedData.prototype._validate = function() {
    this.withEncoding('binary');
  };
  
  // Boolean protocol for testing if valid
  EncodedData.prototype.isValid = function() {
    try {
      this.validate();
      return true;
    } catch (e) {
      return false;
    }
  };
  
  // subclasses can override to do more stuff
  EncodedData.prototype.validate = function() {
    this._validate();
  };
  
  // convert to a string (in base58 form)
  EncodedData.prototype.toString = function() {
    return this.as('base58');
  };
  
  // convert to a string (in bech32 form)
  EncodedData.prototype.toString = function() {
    return this.as('bech32');
  };
  
  // utility
  EncodedData.prototype.doAsBinary = function(callback) {
    var oldEncoding = this.encoding();
    this.encoding('binary');
    callback.apply(this);
    this.encoding(oldEncoding);
  };
  
  // Setup support for various address encodings.  The object for
  // each encoding inherits from the EncodedData prototype.  This
  // allows any encoding to override any method...changing the encoding
  // for an instance will change the encoding it inherits from.  Note,
  // this will present some problems for anyone wanting to inherit from
  // EncodedData (we'll deal with that when needed).
  var encodings = {
    'binary': {
      converters: {
        'binary': function() {
          var answer = new Buffer(this.data.length);
          this.data.copy(answer);
          return answer;
        },
        'base58': function() {
          return base58.encode(this.data);
        },
        'bech32': function() {
          return bech32.encode(this.data.prefix,this.data.words);
        },
        'hex': function() {
          return this.data.toString('hex');
        },
      },
  
      _validate: function() {
        //nothing to do here...we make no assumptions about the data
      },
    },
  
    'base58': {
      converters: {
        'binary': function() {
          return base58.decode(this.data);
        },
        'hex': function() {
          return this.withEncoding('binary').as('hex');
        },
      },
    },
   'bech32': {
      converters: {
        'binary': function() {
          return bech32.decode(this.data);
        },
        'hex': function() {
          return this.withEncoding('binary').as('hex');
        },
      },
    },
    'hex': {
      converters: {
        'binary': function() {
          return new Buffer(this.data, 'hex');
        },
        'base58': function() {
          return this.withEncoding('binary').as('base58');
        },
      },
    },
  };
  
  var no_conversion = function() {
    return this.data;
  };
  for (var k in encodings) {
    if (encodings.hasOwnProperty(k)) {
      if (!encodings[k].converters[k])
        encodings[k].converters[k] = no_conversion;
      encodings[k]._encoding = k;
    }
  }
  
  EncodedData.applyEncodingsTo = function(aClass) {
    var tmp = {};
    for (var k in encodings) {
      var enc = encodings[k];
      var obj = Object.create(aClass.prototype);
      for (var j in enc) {
        obj[j] = enc[j];
      }
      tmp[k] = obj;
    }
    aClass.prototype.encodings = tmp;
  };
  
  EncodedData.applyEncodingsTo(EncodedData);
  
  module.exports = EncodedData;
  