module Misc
  COLOR_LIST = %w(#BC80BD #CCEBC5 #FFED6F #8DD3C7 #FFFFB3 #BEBADA #FB8072 #80B1D3 #FDB462 #B3DE69 #FCCDE5 #D9D9D9)

  def self.colors_for(list)
    unused = COLOR_LIST.dup

    used = {}
    colors = list.collect do |elem|
      if used.include? elem
        used[elem]
      else
        color = unused.shift
        used[elem]=color
        color
      end
    end

    [colors, used]
  end

  def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
    i = 0
    re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
      text.split(re).collect do |paragraph|
      i += 1
      str = if i % 2 == 1
              words = paragraph.gsub(/\s+/, "\s").split(" ")
              lines = []
              line = " "*offset
              word = words.shift
              while word
                word = word[0..size-indent-offset-4] + '...' if word.length >= size - indent - offset
                while word and Log.uncolor(line).length + Log.uncolor(word).length <= size - indent
                  line << word << " "
                  word = words.shift
                end
                lines << ((" " * indent) << line[0..-2])
                line = ""
              end
              (lines * "\n")
            else
              paragraph
            end
      offset = 0
      str
      end*""
  end

  def self.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow)
    dd = "" if dd.nil?
    dt = dt.to_s + ":" unless dd.empty?
    dt = Log.color color, dt if color
    len = Log.uncolor(dt).length

    if indent < 0
      text = format_paragraph(dd, size, indent.abs-1, 0)
      text = dt << "\n" << text
    else
      offset = len - indent
      offset = 0 if offset < 0
      text = format_paragraph(dd, size, indent.abs+1, offset)
      text[0..len-1] = dt
    end
    text
  end

  def self.format_definition_list(defs, size = 80, indent = 20, color = :yellow)
    entries = []
    defs.each do |dt,dd|
      text = format_definition_list_item(dt,dd,size,indent,color)
      entries << text
    end
    entries * "\n\n"
  end

  def self.camel_case(string)
    return string if string !~ /_/ && string =~ /[A-Z]+.*/
      string.split(/_|(\d+)/).map{|e| 
        (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize) 
      }.join
  end

  def self.camel_case_lower(string)
      string.split('_').inject([]){ |buffer,e| 
        buffer.push(buffer.empty? ? e.downcase : (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize)) 
      }.join
  end

  def self.snake_case(string)
    return nil if string.nil?
    string = string.to_s if Symbol === string
    string.
      gsub(/([A-Z]{2,})([A-Z][a-z])/,'\1_\2').
      gsub(/([a-z])([A-Z])/,'\1_\2').
      gsub(/\s/,'_').gsub(/[^\w_]/, '').
      split("_").collect{|p| p.match(/[A-Z]{2,}/) ? p : p.downcase } * "_"
  end

  # source: https://gist.github.com/ekdevdes/2450285
  # author: Ethan Kramer (https://github.com/ekdevdes)
  def self.humanize(value, options = {})
    if options.empty?
      options[:format] = :sentence
    end

    values = []
    values = value.split('_')
    values.each_index do |index|
      # lower case each item in array
      # Miguel Vazquez edit: Except for acronyms
      values[index].downcase! unless values[index].match(/[a-zA-Z][A-Z]/)
    end
    if options[:format] == :allcaps
      values.each do |value|
        value.capitalize!
      end

      if options.empty?
        options[:seperator] = " "
      end

      return values.join " "
    end

    if options[:format] == :class
      values.each do |value|
        value.capitalize!
      end

      return values.join ""
    end

    if options[:format] == :sentence
      values[0].capitalize! unless values[0].match(/[a-zA-Z][A-Z]/)

      return values.join " "
    end

    if options[:format] == :nocaps
      return values.join " "
    end
  end

  def self.fixascii(string)
    if string.respond_to?(:encode)
      self.fixutf8(string).encode("ASCII-8BIT") 
    else
      string
    end
  end

  def self.to_utf8(string)
    string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
  end

  def self.fixutf8(string)
    return nil if string.nil?
    return string if (string.respond_to? :valid_encoding? and string.valid_encoding?) or
    (string.respond_to? :valid_encoding and string.valid_encoding)

    if string.respond_to?(:encode)
      string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
    else
      require 'iconv'
      @@ic ||= Iconv.new('UTF-8//IGNORE', 'UTF-8')
      @@ic.iconv(string)
    end
  end

end