#==============================================================================
# □ SPG(SmliP Gospel File Encrypt System) (分割定义 1)
#==============================================================================
# 福音文件加密系统
module SPG
  #--------------------------------------------------------------------------
  # ● 常量
  #--------------------------------------------------------------------------
  # 文件后缀名称
  FILE_NAME_SUFFIX_SPG = ".spg"
  FILE_NAME_SUFFIX_SAVE = ".rxdata"
  #--------------------------------------------------------------------------
  # ● 定义实例变量
  #--------------------------------------------------------------------------
  attr_reader :map_data                    # 全游戏地图初始化数据(只读)
  attr_reader :rxdata                      # 综合数据(只读)
  attr_reader :save_data                   # 存档数据(只读)
  #--------------------------------------------------------------------------
  # ● 更新
  #--------------------------------------------------------------------------
  def self.update
    if @wait_count != nil
      if @wait_count > 0
        @wait_count -= 1
      else
        for l in @logo
          l.visible = false
        end
        @logo[@logo_index].visible = true
        @logo_index += 1
        @logo_index = (@logo_index % 3)
        @wait_count = 3
      end
    end
  end
  #--------------------------------------------------------------------------
  # ● 开始图片进度条
  #     type       : 图片摆放样式(<=0:保存样式 >0:读取样式)
  #--------------------------------------------------------------------------
  def self.start_picture(type = 1)
    @wait_count = 0
    @logo = []
    # 图片摆放样式
    type = type.to_i
    for i in 0...3
      s = Sprite.new
      # 图片摆放样式(<=0:保存样式 >0:读取样式)
      if type <= 0
        s.bitmap = RPG::Cache.picture("LOGO/青蛙游戏/路易/save logo/路易-#{i}.png")
        s.x = 640 - s.bitmap.width
        s.y = 480 - s.bitmap.height
      else
        s.bitmap = RPG::Cache.picture("LOGO/青蛙游戏/路易/load logo/路易-#{i}.png")
        s.x = 640 * 0.5 - s.bitmap.width * 0.5
        s.y = 480 * 0.5 - s.bitmap.height * 0.5
      end
      s.z = 9999
      s.visible = false
      @logo.push(s)
    end
    @logo[0].visible = true
    @logo[1].visible = false
    @logo[2].visible = false
    @logo_index = 0
  end
  #--------------------------------------------------------------------------
  # ● 结束图片进度条
  #--------------------------------------------------------------------------
  def self.end_picture
    @wait_count = nil
    if @logo != nil
      for l in @logo
        l.dispose if l != nil
      end
    end
  end
  #--------------------------------------------------------------------------
  # ● 执行加解密
  #     type       : 加解密方式(<=0:加密方式 >=1:解密方式(保存为文件) >=2:解密方式(直接读取解密后的文件数据))
  #     file_name  : 需要处理的文件名
  #     password   : 密匙字符串(范围:1-0、A-Z、a-z)(作为执行加解密的指令方式,可以是多位)
  #--------------------------------------------------------------------------
  def self.start(type, file_name, password = "")
begin
    type = type.to_i
    password = password.to_s
    # 大写字母
    edh_upcase = ["A","B","C","D","E","F","G","H","I","J","K","L","M",
                  "N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ]
    # 大写字母
    edh_downcase = ["A","B","C","D","E","F","G","H","I","J","K","L","M",
                    "N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ]
    edh_numeric = ["1","2","3","4","5","6","7","8","9","0"]
    filename_object = "#{file_name}"
    filename_new = "#{filename_object}" + "_new"
    # 文件不存在的情况下
    unless FileTest.exist?(filename_object)
      return false
    end
    object = File.open(filename_object, "rb")
    # 存储源文件数据用数组
    object_data = object.readlines.clone
    object.close
    # 层数上限
    code_max = 20
    # 自校检随机值库存
    rand_code_data = []
    # 加解密次数
    encrypt_num = 5
    # 解密
    if type >= 1
      # 解压缩的方式读取文件
      object = Zlib::GzipReader.open(filename_object)
      #object = File.open(filename_object, "rb")
      # 自定义字符串
      by_text = Marshal.load(object)
      for i in 1..code_max
        # 读取
        rand_code_data.push(Marshal.load(object))
      end
      nil_value = 0
      for i in 0...rand_code_data.size
        # 读取
        nil_value += 1 if rand_code_data[i] == nil
      end
      # 读入各种对像
      object_new = Marshal.load(object)
      # (有自定义密匙的情况下)
      if nil_value == 0
        result_value = 0
        for i in 0...rand_code_data.size
          # 数值化
          result_value += self.code_list(rand_code_data[i])[0][0, 1].to_i
        end
        # 求余
        result_value = result_value % code_max
        password = rand_code_data[result_value]
      else
        # 数据下一层是密匙
        password = Marshal.load(object)
      end
      object.close
      code_text = self.code_list(password)
      object_new = [object_new[0]]
      # 进行N次解密操作
      for i in 1..encrypt_num
        object_new = self.code_denote(1, object_new[0], code_text[0])
      end
      return self.load(object_new)
    else
      # ……
    end
rescue
    print("(010)无法运行游戏!请检查文件是否缺少或损坏。")
    exit
end
  end
  #--------------------------------------------------------------------------
  # ● 读取数据
  #     object   : 解密后的对象数据
  #--------------------------------------------------------------------------
  def self.load(object)
    # 代入对象数据
    object_new = object
    # 初始化存值
    file = nil
    for i in 0...object_new[0].size
      # 如果存值是零的情况下(设为零是因为在不确定存值类型的情况下可以自动赋值,从而自动的改变了存值类型)
      if file == nil
        file = object_new[0][i]
      else
        file += object_new[0][i]
      end
    end
    # 读取描绘存档文件用的角色数据
    d = Marshal.load(file)
    return d
  end
  #--------------------------------------------------------------------------
  # ● 码表解析(加解密执行代码)
  #     code_text  : 需要解码的码表字符串
  #--------------------------------------------------------------------------
  def self.code_list(code_text)
    code_text = code_text.to_s
    result_code = ""
    for i in 0...code_text.size
      # 获取一个字符串
      case code_text[i, 1]
      when "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" # 数值(1-0)
        result_code += code_text[i, 1]
      when "A" # 大写(A-Z)
        result_code += "0"
      when "B"
        result_code += "1"
      when "C"
        result_code += "2"
      when "D"
        result_code += "3"
      when "E"
        result_code += "4"
      when "F"
        result_code += "5"
      when "G"
        result_code += "6"
      when "H"
        result_code += "7"
      when "I"
        result_code += "8"
      when "J"
        result_code += "9"
      when "K"
        result_code += "10"
      when "L"
        result_code += "11"
      when "M"
        result_code += "12"
      when "N"
        result_code += "13"
      when "O"
        result_code += "14"
      when "P"
        result_code += "15"
      when "Q"
        result_code += "16"
      when "R"
        result_code += "17"
      when "S"
        result_code += "18"
      when "T"
        result_code += "19"
      when "U"
        result_code += "20"
      when "V"
        result_code += "21"
      when "W"
        result_code += "22"
      when "X"
        result_code += "23"
      when "Y"
        result_code += "24"
      when "Z"
        result_code += "25"
      when "a" # 小写(a-z)
        result_code += "26"
      when "b"
        result_code += "27"
      when "c"
        result_code += "28"
      when "d"
        result_code += "29"
      when "e"
        result_code += "30"
      when "f"
        result_code += "31"
      when "g"
        result_code += "32"
      when "h"
        result_code += "33"
      when "i"
        result_code += "34"
      when "j"
        result_code += "35"
      when "k"
        result_code += "36"
      when "l"
        result_code += "37"
      when "m"
        result_code += "38"
      when "n"
        result_code += "39"
      when "o"
        result_code += "40"
      when "p"
        result_code += "41"
      when "q"
        result_code += "42"
      when "r"
        result_code += "43"
      when "s"
        result_code += "44"
      when "t"
        result_code += "45"
      when "u"
        result_code += "46"
      when "v"
        result_code += "47"
      when "w"
        result_code += "48"
      when "x"
        result_code += "49"
      when "y"
        result_code += "50"
      when "z"
        result_code += "51"
      else # 默认的加解密执行方式
        result_code += "312"
      end
    end
    # 返回 已经解码的码表(=>指令表)
    return [result_code]
  end
  #--------------------------------------------------------------------------
  # ● 执行指令表(执行加解密方式)
  #     type        : 加解密方式(<=0:加密方式 >=1:解密方式(保存为文件) >=2:解密方式(直接读取解密后的文件数据))
  #     object      : 对象数据
  #     code_text   : 需要执行的指令表字符串
  #--------------------------------------------------------------------------
  def self.code_denote(type, object, code_text)
    tyep = type.to_i
    code = code_text
    # 获取对象数据
    object_new = [object]
    for i in 0...code.size
      # 解密
      if type >= 1
        # 获取一个字符串并且转换为数值()
        code_value = code[(code.size - 1 - i), 1].to_i 
        # 类型(<=0:加密 >0:解密)
        code_type = 1
      # 加密
      else
        # 获取一个字符串并且转换为数值
        code_value = code[i, 1].to_i 
        # 类型(<=0:加密 >0:解密)
        code_type = 0
      end
      #--------------------------------------------------------------------------
      # ● 方式1:交叉法(执行一次为加密,再执行一次为解密)
      #     object  : 源流数据组
      #     type    : 类型(<=0:加密 >0:解密)
      #     value   : 单元间隔数
      #--------------------------------------------------------------------------
      #--------------------------------------------------------------------------
      # ● 方式2:插入法(首单元删除法)
      #     object  : 源流数据组
      #     type    : 类型(<=0:首单元向尾部前面添加(默认:加密) >0:尾部前面单元向首单元前面添加(默认:解密))
      #     value   : 执行次数
      #--------------------------------------------------------------------------
      #--------------------------------------------------------------------------
      # ● 方式3:插入法(指定单元位移到指定位置上)
      #     object  : 源流数据组
      #     type    : 类型(<=0:指定元向指定位置前面添加(默认:加密) >0:指定位置单元向指定位置上前面添加(默认:解密))
      #     value   : 执行次数
      #     place   : 位移位置([指定位置索引, 位移的所在索引])
      #--------------------------------------------------------------------------
      # 分歧 执行命令
      case code_value
      when 1
begin
        # 方式1:交叉法(执行一次为加密,再执行一次为解密)
        object_new = self.deed_1(object_new[0], code_type)
rescue
        p "错误代码(SPG1)"
end
      when 2
begin
        # 方式2:插入法(首单元删除法)
        object_new = self.deed_2(object_new[0], code_type)
rescue
        p "错误代码(SPG2)"
end
      when 3
begin
        # 方式3:插入法(指定单元位移到指定位置上)
        object_new = self.deed_3(object_new[0], code_type)
rescue
        p "错误代码(SPG3)"
end
      when 4
begin
        object_new = self.deed_1(object_new[0], code_type)
rescue
        p "错误代码(SPG4)"
end
      when 5
begin
        object_new = self.deed_2(object_new[0], code_type, 2)
rescue
        p "错误代码(SPG5)"
end
      when 6
begin
        object_new = self.deed_2(object_new[0], code_type, 3)
rescue
        p "错误代码(SPG6)"
end
      when 7
begin
        object_new = self.deed_3(object_new[0], code_type, 3, [1, 3])
rescue
        p "错误代码(SPG7)"
end
      when 8
begin
        object_new = self.deed_3(object_new[0], code_type, 3, [2, 2])
rescue
        p "错误代码(SPG8)"
end
      when 9
begin
        object_new = self.deed_3(object_new[0], code_type, 3, [3, 1])
rescue
        p "错误代码(SPG9)"
end
      when 0
      else
      end # case 
    end
    # 压缩字符串操作
    for i in 0...object_new[0].size
      if type >= 1
        # 解压
        object_new[0][i] = self.zlib(object_new[0][i], 1)[0]
      else
        # 加压
        # 解压
        object_new[0][i] = self.zlib(object_new[0][i], 0)[0]
      end
    end
    # 更新画面(防错:10秒备份)
    Graphics.update
    return object_new
  end # def 
  #--------------------------------------------------------------------------
  # ● 备份目录下指定类型的所有文件
  #     chdir_name  : 目录名称
  #     type_name   : 文件类型
  #--------------------------------------------------------------------------
  def self.bak_file(chdir_name = "DATA", type_name = "*")
    # 创建的目录名称
    list_name = "Bak"
    # 如果目录不存在的情况下
#    Dir.mkdir("#{list_name}") unless FileTest.directory?("#{list_name}")
    # 获取目录下指定类型文件
    file_name_data = self.file_name("#{chdir_name}","#{type_name}")
    return if file_name_data.empty?
    for file_name in file_name_data
      # 复制文件(备份原文件用)
      self.copy(file_name, "#{list_name}")
    end
  end
  #--------------------------------------------------------------------------
  # ● 获取目录下指定类型文件
  #     chdir_name  : 目录名称
  #     type_name   : 文件类型
  #--------------------------------------------------------------------------
  def self.file_name(chdir_name = "DATA", type_name = "*")
    file_name_data = []
    # 返回到指定目录
    Dir.chdir("#{chdir_name}")
    for file_name in Dir[type_name.to_s]
      file_name_data.push(file_name.to_s) if FileTest.file?(file_name.to_s)
    end
    return file_name_data
  end
  #--------------------------------------------------------------------------
  # ● 复制文件(备份原文件用)
  #     file_name   : 原文件的名称
  #     chdir_name  : 备份的文件夹名称
  #     type_name   : 备份后附加的文件名后缀
  #--------------------------------------------------------------------------
  def self.copy(file_name, chdir_name = "Bak", type_name = ".bak")
    begin
      # 原文件的名称
      out_file = "#{file_name}"
      # 新备份文件的名称
      new_file = "#{chdir_name}/#{out_file}" + "#{type_name}"
      # 文件不存在的情况下
      unless FileTest.exist?(out_file)
        return false
      end
      # 打开源文件
      object = File.open(out_file, "rb")
      # 存储源文件数据用数组
      object_data = []
      # 读取源文件数据
      object.each_line { |o| object_data.push(o) }
      object.close
      return if object_data == []
      # 如果目录不存在的情况下
      Dir.mkdir("#{chdir_name}") if !FileTest.directory?("#{chdir_name}") and chdir_name != ""
      # 建立新文件
      new = File.open(new_file, "wb")
      # 写入读取到的源文件数据到新文件
      object_data.each { |n| new.write(n) }
      new.close
      object_data = []
      # 返回结果
      return true
    # 错误处理
    rescue
      return false
    end
  end
  #--------------------------------------------------------------------------
  # ● 压缩字符串(Zlib)
  #     string  : 需要操作的字符串
  #     type    : 类型(<=0:加压 >0:解压)
  #--------------------------------------------------------------------------
  def self.zlib(string,type)
    # 即时刷新
    self.update
    # 返回 如果不是字符串的情况下
    return [string] unless string.is_a?(String)
    string = string
    new_string = string
    if type >= 1
      new_string = Zlib::Inflate.inflate(string)
    else
      new_string = Zlib::Deflate.deflate(string, (rand(9) + 1))
    end
    return [new_string]
  end
  #--------------------------------------------------------------------------
  # ● 方式1:交叉法(执行一次为加密,再执行一次为解密)
  #     object  : 源流数据组
  #     type    : 类型(<=0:加密 >0:解密)
  #     value   : 单元间隔数
  #--------------------------------------------------------------------------
  def self.deed_1(object, type = 0, value = 2)
    result = false
    # 存储源文件数据用数组
    object_data = object.clone
    object_new = []
    value = value.to_i
    for i in 0...object_data.size
            object_new.push(nil)
    end
    for v in 0...object_data.size
      if v != 0 and v != object_data.size-1
              if (v % value) == 0
                       v0 = (v - 1)
                       v1 = v
                #        p [v,v0,v1]
          object_new[v0] = object_data[v1]
          object_new[v1] = object_data[v0]
          # 类型(<=0:加密 >0:解密)
          if type >= 1
            # Zlib 解压
            object_new[v0] = self.zlib(object_data[v1], 1)[0]
            object_new[v1] = self.zlib(object_data[v0], 1)[0]
          else
            # Zlib 加压
            object_new[v0] = self.zlib(object_data[v1], 0)[0]
            object_new[v1] = self.zlib(object_data[v0], 0)[0]
          end
        else
          object_new[v] = object_data[v]
        end        
      else
        object_new[v] = object_data[v]
      end
      # 更新画面(防错:10秒备份)
      Graphics.update if (v % 5000) == 0
      reslut = true if v == (object_data.size - 1)
    end
    # 返回 ([流数据数组, 结果])
    return [object_new, reslut]
  end # def
  #--------------------------------------------------------------------------
  # ● 方式2:插入法(首单元删除法)
  #     object  : 源流数据组
  #     type    : 类型(<=0:首单元向尾部前面添加(默认:加密) >0:尾部前面单元向首单元前面添加(默认:解密))
  #     value   : 执行次数
  #--------------------------------------------------------------------------
  def self.deed_2(object, type = 0, value = 2)
    result = false
    # 存储源文件数据用数组
    object_data = object
    object_new = object_data.clone
    value = value.to_i
    for v in 1..value
      # 即时刷新
  #    self.update
      # 加密
      if type <= 0
        # 删除并返回首单元
        new = object_new.shift
        new = self.zlib(new, 0)[0]
        # 将已经删除的首单元数据添加到尾部单元的前面
        object_new.insert((object_new.size - 1), new)
        reslut = true if v == value
      # 解密
      else
        # 删除并返回尾部前面的单元
        new = object_new.delete_at((object_new.size - 1 - 1))
        new = self.zlib(new, 1)[0]
        # 将已经删除的尾部前面单元数据添加到首单元前面
        object_new.insert(0, new)
        reslut = true if v == value
      end
    end
    # 返回 ([流数据数组, 结果])
    return [object_new, reslut]
  end # def
  #--------------------------------------------------------------------------
  # ● 方式3:插入法(指定单元位移到指定位置上)
  #     object  : 源流数据组
  #     type    : 类型(<=0:指定元向指定位置前面添加(默认:加密) >0:指定位置单元向指定位置上前面添加(默认:解密))
  #     value   : 执行次数
  #     place   : 位移位置([指定位置索引, 位移的所在索引])
  #                         注意:位置索引按照每行的字节数量而定,一般在1-6左右,超过字节数量上限即出错。
  #--------------------------------------------------------------------------
  def self.deed_3(object, type = 0, value = 2, place = [0, 3])
    result = false
    # 存储源文件数据用数组
    object_data = object
    object_new = object_data.clone
    value = value.to_i
    place = place
    for v in 1..value
      # 即时刷新
   #   self.update
      # 加密
      if type <= 0
        new = object_new.delete_at(place[0])
        new = self.zlib(new, 0)[0]
        object_new.insert(place[1], new)
        reslut = true if v == value
      # 解密
      else
        new = object_new.delete_at(place[1])
        new = self.zlib(new, 1)[0]
        object_new.insert(place[0], new)
        reslut = true if v == value
      end
    end
    # 返回 ([流数据数组, 结果])
    return [object_new, reslut]
  end # def
end # module
# 应用
#SPG.start_change
#SPG.start_script_data