class License
  include HTTParty

  base_uri "connect.smartsales.asia/api"

  attr_accessor :name, :address_1, :address_2, :township, :city, :country, :email, :phone, :fax, :logo, :subdomain,
  :plan_activation_date, :plan_next_renewal_date, :plan_max_products,:plan_max_customers, :plan_active_connections,
  :dbhost, :dbschema, :dbusername, :dbpassword, :exchange_unqiue_id, :localqueue_host,:server_mode,:localhost_address,
  :localqueue_user, :localqueue_password, :remotequeue_host, :remotequeue_user, :remotequeue_password, :api_token, :app_token

  @license = nil
  @secret = nil

  def initialize(server = "", lookup = "")
    #this code is hard-code to reflect server mode - Very important.
    self.server_mode = ENV["SERVER_MODE"]

    if (server != "")
     self.class.base_uri server
    end
  end  

  # For Cloud
  def detail_with_local_cache(lookup)  
    aes = MyAesCrypt.new
    aes_key, aes_iv = aes.export_to_file(lookup)  
    
    ##Check from local redis - if available load local otherwise get from remote
    cache_key = "#{lookup}:license:#{aes_key}:hostname"    

    cache_license = nil

    ##Get redis connection from connection pool
    redis = Redis.new
    cache_license = redis.get(cache_key)    
    
    Rails.logger.info "Cache key - " + cache_key.to_s
    if cache_license.nil?
      ##change the d/e key
      # @options = { query: {device: "SXlite", lookup: lookup, skey: @secret, token: SECRETS_CONFIG['provision_key']} }
      @params = { query: { lookup_type: self.server_mode, lookup: lookup, iv_key: aes_iv} }
      response = self.class.get("/subdomain", @params)
      @license = response.parsed_response

      if (@license["status"] == true)
        assign(aes_key, aes_iv)

        # Rails.logger.info "License - " + response.parsed_response.to_s
        
        redis = Redis.new
        redis.set(cache_key, Marshal.dump(@license))
        # redis.sadd("License:cache:keys", cache_key)
        # Redis.current do |conn|
        #   ##Remote - store the remote response in local redis cache
        #   conn.set(cache_key, Marshal.dump(@license))
        #   ##ADD to List to remove later
        #   conn.sadd("License:cache:keys", cache_key)
        # end

        return true
      end
    else         
      @license = Marshal.load(cache_license)
      assign(aes_key, aes_iv)
      # Rails.logger.info 'API License'           
      return true
    end
  end

  # For Local System
  def detail_with_local_file()    
    renewal_date_str = read_license("renewable_date")
    if check_expiring(renewal_date_str)   
      # return for all ok 
      return 1
    else
      has_license = verify_license()
      if has_license
        # return for expiring 
        return 2
      else
        return 0
      end
    end
    # end    
  end    

  # License Activation
  def license_activate (shop, license_key, db_host, db_schema, db_user, db_password)
    aes = MyAesCrypt.new 
    aes_key, aes_iv = aes.export_key(license_key)     

    @params = { query: { lookup_type: self.server_mode, iv_key: aes_iv, license_key: license_key } }
    response = self.class.get("/activate", @params)
    @activate = response.parsed_response

    if (@activate["status"])
      ##Check from local redis - if available load local otherwise get from remote
      cache_key = "shop:#{@activate["shop_name"]}"    

      cache_license = nil    

      ##Get redis connection from connection pool
      redis = Redis.new
      cache_license = redis.get(cache_key)    

       Rails.logger.info "Cache key - " + cache_key.to_s

      if cache_license.nil?   
        cache = {"shop" => @activate["shop_name"], "key" => aes_key, "iv" => @activate["iv_key"], "renewable_date" => @activate["renewable_date"] }           
        redis = Redis.new
        redis.set(cache_key, Marshal.dump(cache))
      end 

      Rails.logger.info "License - " + response.parsed_response.to_s

      response =  create_license_file(@activate)
      if(response[:status])
        #sym_path = "/home/user/symmetric/"
        sym_path  =  File.expand_path("~/symmetric/")

        response = create_symmetric_config(sym_path, db_host, db_schema, db_user, db_password)
         
        if(response[:status])
          response = run_symmetric(sym_path)
        end
      end
    else
      response = { "status": false, "message": "Activation Failed! Please contact code2lab call center!"}
    end 
    return response
  end

  def verify_license    
    api_token = read_license_no_decrypt("api_token")    
    @params = { query: {lookup_type: "application", api_token: api_token} }
    
    begin
        response = self.class.get("/verify", @params)
        @varified = response.parsed_response
        Rails.logger.debug "License Remote Response - " + response.parsed_response.to_s
        if (@varified["status"])
          if (!check_expired(@varified["renewable_date"]))
            return true
          end
        else
          delete_license_file
        end 

      rescue SocketError => e
        Rails.logger.debug  "In SocketError No Internet connection ! "
        return true
      rescue HTTParty::Error
        Rails.logger.debug  "Server Error HTTParty"
        return true
      rescue Net::OpenTimeout
         Rails.logger.debug  "connection Timeout"
        return true
      rescue OpenURI::HTTPError
        Rails.logger.debug  "Can't connect server"
        return true
    end 
    return false  
  end


  # Check Expired before 30 days
  def check_expiring(renewal_date_str)        
    if !renewal_date_str.empty?
      renewal_date = DateTime.parse(renewal_date_str)    
      renewal_date >  Date.today.advance(:days => 30)
    end
  end

  # Check License expired date from PROVISION SERVER
  def check_expired(renewal_date_str)    
    expired_date_str = read_license("renewable_date")
    renewal_date = DateTime.parse(renewal_date_str)
    if(renewal_date_str != expired_date_str)
      update_license("renewable_date", renewal_date_str)
    end

    if (renewal_date < Date.today)
      return true
    else
      return false
    end
  end
  
  # Check License File exists
  def self.check_license_file
    return File.exist?("config/license.yml")      
  end

  # read line by key for license file
  def read_license(key_name)    
    decrypted_line = "" 
    key, iv = get_redis_key()

    if File.exist?("config/license.yml")  
      File.open("config/license.yml").each do |line|
        if line.include? (key_name)      
          decrypted_line_array = line.split(": ")                            
          decrypted_line = AESCrypt.decrypt_data(decode_str(decrypted_line_array[1]), decode_str(key), decode_str(iv), ENV['CIPHER_TYPE'])
        end
      end
    end    
    return decrypted_line
  end

  # read line by key for license file without decrypt
  def read_license_no_decrypt(key)
    decrypted_line = ""
    if File.exist?("config/license.yml")  
      File.open("config/license.yml").each do |line|
        if line.include? (key)
          decrypted_line_array = line.split(": ")
          decrypted_line = decrypted_line_array[1]
        end
      end
    end
    return decrypted_line
  end

  # Update license file for line
  def update_license(content, new_content)
    key, iv = get_redis_key()

    if !new_content.include? "=="      
      crypted_str = AESCrypt.encrypt_data(new_content, decode_str(key), decode_str(iv), ENV['CIPHER_TYPE'])
    end
    
    content_str = read_license_no_decrypt(content)
    if File.exist?("config/license.yml")  
      file_str = File.read("config/license.yml")
      new_file_str = file_str.gsub(content_str, encode_str(crypted_str))

      # To write changes to the file, use:
      File.open("config/license.yml", "w") {|file| file.puts new_file_str }
      
      # File.open("config/license.yml").each do |line|
      #   new_file_str = line.gsub(content, crypted_str)
      #   f.put
      # end
    end
  end

  # Re-get keys
  def get_key
    api_token = read_license_no_decrypt("api_token")  
    shop_name = read_license_no_decrypt("shop_name")    
    @params = { query: {lookup_type: "application", api_token: api_token } }
    response = self.class.get("/get_key", @params)
    @data = response.parsed_response
    
    if (@data["status"])
      ##Check from local redis - if available load local otherwise get from remote
      cache_key = "shop:#{shop_name.chomp}"    

      cache_license = nil    

      ##Get redis connection from connection pool
      redis = Redis.new
      cache_license = redis.get(cache_key)    

       Rails.logger.info "Cache key - " + cache_key.to_s

      if cache_license.nil?   
        cache = {"shop" => shop_name, "key" => @data["secret_key"], "iv" => @data["iv_key"], "renewable_date" => @data["renewable_date"] }           
        redis = Redis.new
        redis.set(cache_key, Marshal.dump(cache))
      end 
      return true
    end 
    return false
  end  

  private
  def get_redis_key
    iv = ""
    key = ""
    shop = read_license_no_decrypt("shop_name")
    ##Check from local redis - if available load local otherwise get from remote
    cache_key = "shop:#{shop.chomp}"     

    cache_shop = nil    

    ##Get redis connection from connection pool
    redis = Redis.new
    cache_shop = redis.get(cache_key)    

    if !cache_shop.nil? 
      @shop = Marshal.load(cache_shop) 
      key = @shop["key"] 
      iv = @shop["iv"] 
    end
    return key, iv
  end

  def encode_str(str)
    return Base64.encode64(str)
  end

  def decode_str(str)
    return Base64.decode64(str)
  end

  # License File Creation
  def create_license_file(response_data)
    if File.exist?("config/license.yml") 
      delete_license_file
    end

    begin
      # Licese File Creation
      File.open("config/license.yml", "w") do |f|    
        f.puts("iv_key: #{response_data['iv_key']}")
        f.puts("shop_name: #{response_data['shop_name']}")
        f.puts("email: #{response_data['email']}")
        f.puts("telephone: #{response_data['telephone']}")
        f.puts("fax: #{response_data['fax']}")
        f.puts("address: #{response_data['address']}")
        f.puts("dbhost: #{response_data['dbhost']}")
        f.puts("dbschema: #{response_data['dbschema']}")
        f.puts("dbusername: #{response_data['dbusername']}")
        f.puts("dbpassword: #{response_data['dbpassword']}")
        f.puts("api_token: #{response_data['api_token']}")
        f.puts("app_token: #{response_data['app_token']}")  
        f.puts("plan_sku: #{response_data['plan_sku']}")
        f.puts("renewable_date: #{response_data['renewable_date']}")
        f.puts("plan_name: #{response_data['plan_name']}")
      end          
    rescue IOError
       response = { "status": false, "message": "Activation is success but something is wrong. \n Please contact code2lab call center!"}
    end
    response = { "status": true, "message": "Success Activation. License also created."}
  end

  # Symmetric Configuration
  def create_symmetric_config(sym_location, db_host, db_schema, db_user, db_password)
    if File.directory? (sym_location)
      begin
        # sx properties create
        f = File.open(sym_location + "/engines/sx.properties", "w")
        f.write("engine.name=sx\n")
        f.write("db.driver=com.mysql.jdbc.Driver\n")
        f.write("db.url=jdbc:mysql://#{db_host}/#{db_schema}?tinyInt1isBit=false\n")
        f.write("db.user=#{db_user}\n")
        f.write("db.password=#{db_password}\n")
        f.write("registration.url=\n")
        f.write("sync.url=http://#{db_host}:31415/sync/sx\n")
        f.write("group.id=sx\n")
        f.write("external.id=000\n")
        f.write("job.purge.period.time.ms=7200000\n")
        f.write("job.routing.period.time.ms=5000\n")  
        f.write("job.push.period.time.ms=10000\n")  
        f.write("job.pull.period.time.ms=10000\n")  
        f.write("initial.load.create.first=true\n")  
        f.write("initial.load.use.extract.job.enabled=true\n")
        f.write("rest.api.enable=true\n")
        f.close 

        # read from license file 
        # shop_name = read_license_no_decrypt("shop_name")
        shop_name = "cloud"
        dbhost = read_license("dbhost")
        dbschema = read_license("dbschema")
        dbusername = read_license("dbusername")
        dbpassword = read_license("dbpassword")

        # shop properties create
        f = File.open(sym_location + "/engines/#{shop_name}.properties", "w")
        f.write("engine.name=#{shop_name}\n")
        f.write("db.driver=com.mysql.jdbc.Driver\n")
        f.write("db.url=jdbc:mysql://#{dbhost}/#{dbschema}?tinyInt1isBit=false\n")
        f.write("db.user=#{dbusername}\n")
        f.write("db.password=#{dbpassword}\n")
        f.write("registration.url=http://#{db_host}:31415/sync/sx\n")
        f.write("group.id=cloud\n")
        f.write("external.id=001\n")
        f.write("job.routing.period.time.ms=5000\n")  
        f.write("job.push.period.time.ms=10000\n")  
        f.write("job.pull.period.time.ms=10000\n")
        f.write("rest.api.enable=true\n")
        # f.write("initial.load.create.first=true\n")  
        # f.write("initial.load.use.extract.job.enabled=true\n")         
        f.close
      rescue IOError
         response = { "status": false, "message": "Activation is success but something is wrong. \n Please contact code2lab call center!"}
      end
      response = { "status": true, "message": "Success Activation. License also created."}
    end
  end

  # Run Symmetric 
  def run_symmetric(sym_path)
    # check_sym_proc_str = `#{sym_path + "bin/sym_service status"}`
    # check_sym_proc_str = check_sym_proc_str.split("\n")
    # sym_install_status = check_sym_proc_str[0].split(": ")
    
    check_sym_proc_str = `#{"sudo service SymmetricDS status"}`

    # Check Sym Installed
    # if sym_install_status[1] == "false"
    #   response = { "status": false, "message": "Activation is success but Symmetric service not Installed. \n Please contact code2lab call center!"}
    # end

    # Run Sym Service
    sym_run_status = check_sym_running(check_sym_proc_str, sym_path)
    if sym_run_status
      # Create Sym Table
      check_sym_table = system("sudo " + sym_path + "/bin/symadmin --engine sx create-sym-tables")
      if check_sym_table
        sym_sql = Rails.root + "db/sym_master.sql"
        
        if File.exist? (sym_sql)
          # Import Sym Sql to db and start sym
          run_sym_sql = system("sudo " + sym_path + "/bin/dbimport --engine sx " + sym_sql.to_s)
          stop_sym = system("sudo service SymmetricDS stop")
          run_sym = system("sudo service SymmetricDS start")
          if run_sym
            response = { "status": true, "message": "Activation is success and Configuration done..."}
          end
        else
          response = { "status": false, "message": "Activation is success but Symmetric Sql not found. \n Please contact code2lab call center!"}
        end
      else
        response = { "status": false, "message": "Activation is success but Cannot create Sym Tables. \n Please contact code2lab call center!"}
      end
    else      
      response = { "status": false, "message": "Activation is success but Symmetric not running. \n Please contact code2lab call center!"}
    end
  end

  # Check Symmetric Running
  def check_sym_running(status, sym_path)
    # Run Sym Service
    # if status.include? "Server is already running" 
    #   return true
    # elsif status.include? "false"
    #   sym_start_str = `#{sym_path + "bin/sym_service start"}`
    #   if sym_start_str.include? "Started"
    #     return true
    #   else
    #     check_sym_running(sym_start_status[0])
    #   end  
    # else
    #   return true      
    # end

    if status.include? "Active: active (running)" || "Active: active (exited)"   #"Server is already running"
      return true
    end
    return false
  end

  # Delete License File
  def delete_license_file
    File.delete("config/license.yml") if File.exist?("config/license.yml")   
  end

    # Assign db info for Cloud
  def assign(aes_key, aes_iv)    
    key = Base64.decode64(aes_key)
    iv = Base64.decode64(aes_iv)
    
    if (@license["dbhost"] || @license["dbschema"] || @license["dbusername"] || @license["dbpassword"] )           
      host = Base64.decode64(@license["dbhost"])
      dbschema = Base64.decode64(@license["dbschema"])
      dbusername = Base64.decode64(@license["dbusername"])
      dbpassword = Base64.decode64(@license["dbpassword"])

      self.dbhost = AESCrypt.decrypt_data(host, key, iv, ENV['CIPHER_TYPE'])
      self.dbschema = AESCrypt.decrypt_data(dbschema, key, iv, ENV['CIPHER_TYPE'])
      self.dbusername = AESCrypt.decrypt_data(dbusername, key, iv, ENV['CIPHER_TYPE'])
      self.dbpassword = AESCrypt.decrypt_data(dbpassword, key, iv, ENV['CIPHER_TYPE'])      
    end
    
  end
end
