require 'rqrcode'
require 'barby/barcode'

module Barby


  #QrCode is a thin wrapper around the RQRCode library
  class QrCode < Barcode2D

    #Maximum sizes for each correction level for binary data
    #It's an array
    SIZES = {
            #L   M   Q   H
      1  => [17, 14, 11, 7],          2  => [32, 26, 20, 14],
      3  => [53, 42, 32, 24],         4  => [78, 62, 46, 34],
      5  => [106, 84, 60, 44],        6  => [134, 106, 74, 58],
      7  => [154, 122, 86, 64],       8  => [192, 152, 108, 84],
      9  => [230, 180, 130, 98],      10 => [271, 213, 151, 119],
      11 => [321, 251, 177, 137],     12 => [367, 287, 203, 155],
      13 => [425, 331, 241, 177],     14 => [458, 362, 258, 194],
      15 => [520, 412, 292, 220],     16 => [586, 450, 322, 250],
      17 => [644, 504, 364, 280],     18 => [718, 560, 394, 310],
      19 => [792, 624, 442, 338],     20 => [858, 666, 482, 382],
      21 => [929, 711, 509, 403],     22 => [1003, 779, 565, 439],
      23 => [1091, 857, 611, 461],    24 => [1171, 911, 661, 511],
      25 => [1273, 997, 715, 535],    26 => [1367, 1059, 751, 593],
      27 => [1465, 1125, 805, 625],   28 => [1528, 1190, 868, 658],
      29 => [1628, 1264, 908, 698],   30 => [1732, 1370, 982, 742],
      31 => [1840, 1452, 1030, 790],  32 => [1952, 1538, 1112, 842],
      33 => [2068, 1628, 1168, 898],  34 => [2188, 1722, 1228, 958],
      35 => [2303, 1809, 1283, 983],  36 => [2431, 1911, 1351, 1051],
      37 => [2563, 1989, 1423, 1093], 38 => [2699, 2099, 1499, 1139],
      39 => [2809, 2213, 1579, 1219], 40 => [2953, 2331, 1663, 1273]
    }.sort

    LEVELS = { :l => 0, :m => 1, :q => 2, :h => 3 }

    attr_reader :data
    attr_writer :level, :size


    def initialize(data, options={})
      self.data = data
      @level, @size = nil
      options.each{|k,v| send("#{k}=", v) }
      raise(ArgumentError, "data too large") unless size
    end


    def data=(data)
      @data = data
    end


    def encoding
      rqrcode.modules.map{|r| r.inject(''){|s,m| s << (m ? '1' : '0') } }
    end


    #Error correction level
    #Can be one of [:l, :m, :q, :h] (7%, 15%, 25%, 30%)
    def level
      @level || :l
    end


    def size
      #@size is only used for manual override, if it's not set
      #manually the size is always dynamic, calculated from the
      #length of the data
      return @size if @size

      level_index = LEVELS[level]
      length = data.bytesize
      found_size = nil
      SIZES.each do |size,max_values|
        if max_values[level_index] >= length
          found_size = size
          break
        end
      end
      found_size
    end


    def to_s
      data[0,20]
    end


  private
  
    #Generate an RQRCode object with the available values
    def rqrcode
      RQRCode::QRCode.new(data, :level => level, :size => size)
    end


  end


end
