# Ruby Calculator - Interactive calculator built with Ruby on Rails
# Author: RSK World (Molla Samser, Founder | Rima Khatun, Designer & Tester)
# Contact: help@rskworld.in | +91 93305 39277
# Website: https://rskworld.in
# Year: 2026
# Description: Build a fully functional calculator using Ruby on Rails with modern UI

class ProgrammingCalculator
  BASES = {
    binary: 2,
    octal: 8,
    decimal: 10,
    hexadecimal: 16
  }
  
  def self.convert_number(number, from_base, to_base)
    return nil unless BASES.values.include?(from_base) && BASES.values.include?(to_base)
    
    # Convert to decimal first
    decimal_value = to_decimal(number, from_base)
    return nil if decimal_value.nil?
    
    # Then convert to target base
    from_decimal(decimal_value, to_base)
  end
  
  def self.to_decimal(number, base)
    case base
    when 2
      # Binary to decimal
      number.to_s(2).to_i(2)
    when 8
      # Octal to decimal
      number.to_s(8).to_i(8)
    when 10
      # Decimal to decimal
      number.to_i
    when 16
      # Hexadecimal to decimal
      number.to_s(16).to_i(16)
    else
      nil
    end
  rescue
    nil
  end
  
  def self.from_decimal(decimal, base)
    case base
    when 2
      decimal.to_i.to_s(2)
    when 8
      decimal.to_i.to_s(8)
    when 10
      decimal.to_i.to_s
    when 16
      decimal.to_i.to_s(16).upcase
    else
      nil
    end
  rescue
    nil
  end
  
  def self.bitwise_operations(num1, num2, operation)
    dec1 = num1.to_i(2)
    dec2 = num2.to_i(2)
    
    result = case operation
             when 'AND'
               dec1 & dec2
             when 'OR'
               dec1 | dec2
             when 'XOR'
               dec1 ^ dec2
             when 'NOT'
               ~dec1
             when 'LEFT_SHIFT'
               dec1 << dec2
             when 'RIGHT_SHIFT'
               dec1 >> dec2
             else
               nil
             end
    
    {
      binary: result.to_s(2),
      decimal: result,
      hexadecimal: result.to_s(16).upcase,
      octal: result.to_s(8)
    }
  end
  
  def self.get_all_formats(number)
    decimal = number.to_i(10)
    
    {
      binary: decimal.to_s(2),
      octal: decimal.to_s(8),
      decimal: decimal.to_s,
      hexadecimal: decimal.to_s(16).upcase,
      ascii: get_ascii_char(decimal)
    }
  end
  
  def self.get_ascii_char(decimal)
    return 'N/A' if decimal < 0 || decimal > 127
    decimal.chr rescue 'N/A'
  end
  
  def self.calculate_with_base(num1, num2, operation, base)
    dec1 = to_decimal(num1, base)
    dec2 = to_decimal(num2, base)
    
    return nil if dec1.nil? || dec2.nil?
    
    result = case operation
             when '+'
               dec1 + dec2
             when '-'
               dec1 - dec2
             when '*'
               dec1 * dec2
             when '/'
               dec2 != 0 ? dec1 / dec2 : nil
             else
               nil
             end
    
    if result
      {
        result_base: from_decimal(result, base),
        result_decimal: result,
        result_binary: from_decimal(result, 2),
        result_octal: from_decimal(result, 8),
        result_hexadecimal: from_decimal(result, 16)
      }
    else
      nil
    end
  end
  
  def self.twos_complement(number, bits = 8)
    decimal = number.to_i(2)
    
    if decimal >= 2**(bits - 1)
      # Negative number
      result = decimal - 2**bits
      {
        decimal: result,
        binary: result.to_s(2).rjust(bits, '1')[-bits, bits],
        is_negative: true
      }
    else
      # Positive number
      {
        decimal: decimal,
        binary: decimal.to_s(2).rjust(bits, '0'),
        is_negative: false
      }
    end
  end
  
  def self.ones_complement(number, bits = 8)
    binary = number.to_s(2).rjust(bits, '0')
    inverted = binary.chars.map { |bit| bit == '0' ? '1' : '0' }.join
    
    {
      original: binary,
      complement: inverted,
      decimal_original: binary.to_i(2),
      decimal_complement: inverted.to_i(2)
    }
  end
  
  def self.gray_code_to_binary(gray)
    binary = gray[0]
    (1..gray.length-1).each do |i|
      binary += (gray[i-1].to_i ^ gray[i].to_i).to_s
    end
    binary
  end
  
  def self.binary_to_gray_code(binary)
    gray = binary[0]
    (1..binary.length-1).each do |i|
      gray += (binary[i-1].to_i ^ binary[i].to_i).to_s
    end
    gray
  end
  
  def self.calculate_checksum(data)
    bytes = data.unpack('C*')
    checksum = bytes.reduce(:+) & 0xFF
    {
      data: data,
      checksum: checksum,
      checksum_hex: checksum.to_s(16).upcase.rjust(2, '0'),
      checksum_binary: checksum.to_s(2).rjust(8, '0')
    }
  end
  
  def self.hamming_distance(str1, str2)
    return nil if str1.length != str2.length
    
    xor_result = str1.to_i(2) ^ str2.to_i(2)
    xor_result.to_s(2).count('1')
  end
  
  def self.is_power_of_two(number)
    n = number.to_i
    n > 0 && (n & (n - 1)) == 0
  end
  
  def self.next_power_of_two(number)
    n = number.to_i
    return 1 if n == 0
    n -= 1
    n |= n >> 1
    n |= n >> 2
    n |= n >> 4
    n |= n >> 8
    n |= n >> 16
    n += 1
  end
  
  def self.count_set_bits(number)
    n = number.to_i
    count = 0
    while n > 0
      count += 1 if n & 1 == 1
      n >>= 1
    end
    count
  end
  
  def self.reverse_bits(number, bits = 32)
    n = number.to_i
    reversed = 0
    
    bits.times do |i|
      reversed = (reversed << 1) | (n & 1)
      n >>= 1
    end
    
    reversed
  end
end
