text: # -*- coding: utf-8 -*-
  '''
  --------------------------------------
  @Version   : 20.0425.00
  @Author    : hrp
  @Desciption: RnameTool的任务模块。
  --------------------------------------
  '''
  
  import os
  import re
  from time import localtime, strftime
  
  from RenameTool.run.Logger import wLog
  
  osSep = os.sep
  
  
  class Task(object):
      MAX_NAME = 255
      __ESCAPE = {
          r'^': r'\^',
          r'$': r'\$',
          r'(': r'\(',
          r')': r'\)',
          r'-': r'\-',
          r'[': r'\[',
          r']': r'\]',
          r'{': r'\}',
          r'.': r'\.',
          r'+': r'\+',
          r',': r'\,',
      }
  
      def __init__(self, title, target, statedict):
          self.target = target
          self.stdict = statedict
  
          excfd = (
              '，'.join(
                  [
                      i + osSep if os.path.isdir(i) else i
                      for i in statedict['excfd']
                  ]
              )
              if statedict['excfd']
              else '无'
          )
  
          self.title = (
              f'目标：< {target}{osSep} >\n排除：< {excfd} >\n{title}\n{"-" * 50}'
          )
  
          self._successful = dict()
          self._failed = dict()
          self._unchanged = list()
          self._PREVIEWED = False
          self.RENAMED = False
  
      def __allfile(self):
          '''
          返回值是排除用户要排除的文件或文件夹、扩展名(指定或排除)后得到的所有文件路径。
          :return full_path_list: 目标目录下的完整文件路径列表，该列表排除了用户输入的需要排除的子目录。
          '''
          full_path_list = list()
  
          for root, dirs, files in os.walk(self.target, topdown=True):
              if root in self.stdict['excfd']:
                  dirs.clear()
                  continue
  
              for i in files:
                  if os.path.join(root, i) in self.stdict['excfd']:
                      continue
  
                  if not self.stdict['exts']:
                      full_path_list.append(os.path.join(root, i))
  
                  elif self.stdict['inexcext'] == '指定文件格式':
                      if os.path.splitext(i)[1] in self.stdict['exts']:
                          full_path_list.append(os.path.join(root, i))
  
                  elif self.stdict['inexcext'] == '排除文件格式':
                      if os.path.splitext(i)[1] not in self.stdict['exts']:
                          full_path_list.append(os.path.join(root, i))
  
                  else:
                      raise ValueError('指定或排除扩展名选项出错了…')
  
          return full_path_list
  
      def __rename(self):
          '''
          根据successful列表重命名文件。
          重命名失败则把'路径+文件名'从'成功'列表移到'失败'列表。
          设置任务的'已重命名'标志为True。
          '''
          rnlog = wLog('历史记录测试')
          for k, v in self._successful.items():
              try:
                  os.rename(k, v)
                  rnlog.write(k, v)
              except OSError:
                  self._failed[k] = self._successful.pop(k)
          rnlog.close()
          self.RENAMED = True
  
      def __rng_str(self, string, rrepllb, rreplrb):
          '''
          寻找符合给定范围的字符串(最少匹配)，
          并返回找到的字符串列表。
          :param string: 需要匹配的原字符串。
          :param rrepllb: 范围的左边界。
          :param rreplrb: 范围的右边界。
          :return srcs: 匹配到的字符串列表。
          '''
          if self.stdict['word']:
              pt = fr'{rrepllb}\S+{rreplrb}'
          else:
              pt = fr'{rrepllb}.+{rreplrb}'
  
          srcs = re.findall(pt, string)
  
          return srcs
  
      def __rng_num(self):
          '''
          输入数字范围进行替换。
          '''
          pass
  
      def __repl_str(self, string, srcs, repl):
          for src in srcs:
              if self.stdict['word']:
                  string = re.sub(
                      fr'(?<=\s){src}(?=\s|$)|(?<=^){src}(?=\s|$)', repl, string
                  )
              else:
                  string = re.sub(f'{src}', repl, string)
  
          return string
  
      def __ins_with_pos(self, string, instext, pos):
          string = ''.join((string[:pos], instext, string[pos:]))
  
          return string
  
      def __kill_srcs(self, string, srcs, repl):
          for src in srcs:
              string = string.replace(src, repl)
  
          return string
  
      def __repl(self):
          spinf = self.stdict['spinf']
          srcs = [i.replace(r'\k', ' ') for i in self.stdict['srcs']]
  
          for ind in range(len(srcs)):
              for k, v in self.__ESCAPE.items():
                  srcs[ind] = srcs[ind].replace(k, v)
  
          repl = self.stdict['repl']
  
          for fullpath in self.__allfile():
              folder = os.path.dirname(fullpath)
              filename, ext = os.path.splitext(os.path.basename(fullpath))
  
              if spinf == '不含扩展名':
                  filename = self.__repl_str(filename, srcs, repl)
  
              elif spinf == '仅限扩展名':
                  ext = self.__repl_str(ext, srcs, repl)
  
              elif spinf == '全部：独立':
                  filename = self.__repl_str(filename, srcs, repl)
                  ext = self.__repl_str(ext, srcs, repl)
  
              elif spinf == '全部：整体':
                  filename, ext = filename + ext, ''
                  filename = self.__repl_str(filename, srcs, repl)
  
              fullpath_new = os.path.join(folder, filename + ext)
  
              if (set(filename + ext) != '.') and (
                  len(fullpath_new) <= self.MAX_NAME
              ):
                  if fullpath != fullpath_new:
                      if fullpath_new not in self._successful.values() and not os.path.exists(
                          fullpath_new
                      ):
                          self._successful[fullpath] = fullpath_new
                      else:
                          self._failed[fullpath] = fullpath_new
                  else:
                      self._unchanged.append(fullpath)
              else:
                  self._failed[fullpath] = fullpath_new
  
      def __rrepl(self):
          rrepllb = self.stdict['rrepllb']
          rreplrb = self.stdict['rreplrb']
  
          for k, v in self.__ESCAPE.items():
              rrepllb = rrepllb.replace(k, v)
              rreplrb = rreplrb.replace(k, v)
  
          if not rrepllb:
              rrepllb = '^'
          if not rreplrb:
              rreplrb = '$'
  
          repl = self.stdict['repl']
          spinf = self.stdict['spinf']
  
          if not self.stdict['inclb']:
              repl = rrepllb + repl
          if not self.stdict['incrb']:
              repl += rreplrb
  
          for fullpath in self.__allfile():
              folder = os.path.dirname(fullpath)
              filename, ext = os.path.splitext(os.path.basename(fullpath))
  
              if spinf == '不含扩展名':
                  srcs = self.__rng_str(filename, rrepllb, rreplrb)
                  filename = self.__kill_srcs(filename, srcs, repl)
  
              elif spinf == '仅限扩展名':
                  srcs = self.__rng_str(ext, rrepllb, rreplrb)
                  ext = self.__kill_srcs(ext, srcs, repl)
  
              elif spinf == '全部：独立':
                  srcs = self.__rng_str(filename, rrepllb, rreplrb)
                  filename = self.__kill_srcs(filename, srcs, repl)
                  srcs = self.__rng_str(ext, rrepllb, rreplrb)
                  ext = self.__kill_srcs(ext, srcs, repl)
  
              elif spinf == '全部：整体':
                  filename, ext = filename + ext, ''
                  srcs = self.__rng_str(filename, rrepllb, rreplrb)
                  filename = self.__kill_srcs(filename, srcs, repl)
  
              fullpath_new = os.path.join(folder, filename + ext)
  
              if (set(filename + ext) != '.') and (
                  len(fullpath_new) <= self.MAX_NAME
              ):
                  if fullpath != fullpath_new:
                      if fullpath_new not in self._successful.values() and not os.path.exists(
                          fullpath_new
                      ):
                          self._successful[fullpath] = fullpath_new
                      else:
                          self._failed[fullpath] = fullpath_new
                  else:
                      self._unchanged.append(fullpath)
              else:
                  self._failed[fullpath] = fullpath_new
  
      def __ins(self):
          # 已知欠考虑的问题：插入序号时目标文件夹内的文件，包括子文件夹内的文件，只会按一条序号线递增，
          # 不会按子文件夹为分类来新建不同的序号线。
          insertwith = self.stdict['insertwith']
          form = self.stdict['form']
          spinf = self.stdict['spinf']
          instance_pos = isinstance(self.stdict['insertpos'], float)
  
          if insertwith == '日期时间':
              str_to_ins = strftime(form, localtime())
  
          elif insertwith == '普通字符':
              str_to_ins = form
  
          elif insertwith == '数字序号':
              re_sch = re.search(
                  r'<([0-9]{1,10}\.[0-9]{1,10}\.[1-9]{1,10})>', form
              )
              begin, step, wid = map(int, re_sch.group(1).split('.'))
  
          for fullpath in self.__allfile():
              if insertwith == '数字序号':
                  str_to_ins = form.replace(
                      re_sch.group(), f'{str(begin):0>{wid}}'
                  )
  
              folder = os.path.dirname(fullpath)
              filename, ext = os.path.splitext(os.path.basename(fullpath))
              filename_length = len(filename)
              ext_length = len(ext)
              insertpos = self.stdict['insertpos']
  
              if spinf == '不含扩展名':
                  if filename:
                      if instance_pos:
                          insertpos = int(filename_length * insertpos)
  
                      if insertpos > filename_length:
                          insertpos = filename_length
  
                      filename = self.__ins_with_pos(
                          filename, str_to_ins, insertpos
                      )
                  else:
                      filename = str_to_ins
  
              elif spinf == '仅限扩展名':
                  if ext:
                      if instance_pos:
                          insertpos = int(ext_length * insertpos) + 1
  
                      if insertpos > ext_length:
                          insertpos = ext_length
                      ext = self.__ins_with_pos(ext, str_to_ins, insertpos)
                  else:
                      ext = str_to_ins
  
              elif spinf == '全部：独立':
                  if filename:
                      if instance_pos:
                          insertpos = int(filename_length * insertpos)
  
                      if insertpos > filename_length:
                          insertpos = filename_length
  
                      filename = self.__ins_with_pos(
                          filename, str_to_ins, insertpos
                      )
                  else:
                      filename = str_to_ins
  
                  if ext:
                      if instance_pos:
                          insertpos = int(ext_length * insertpos) + 1
  
                      if insertpos > ext_length:
                          insertpos = ext_length
  
                      ext = self.__ins_with_pos(ext, str_to_ins, insertpos)
                  else:
                      ext = str_to_ins
  
              elif spinf == '全部：整体':
                  filename, ext = filename + ext, ''
  
                  if filename:
                      if instance_pos:
                          insertpos = int(
                              (filename_length + ext_length) * insertpos
                          )
  
                      if insertpos > (filename_length + ext_length):
                          insertpos = filename_length + ext_length
  
                      filename = self.__ins_with_pos(
                          filename, str_to_ins, insertpos
                      )
                  else:
                      filename = str_to_ins
  
              fullpath_new = os.path.join(folder, filename + ext)
  
              if (set(filename + ext) != '.') and (
                  len(fullpath_new) <= self.MAX_NAME
              ):
                  if fullpath_new != fullpath:
                      if fullpath_new not in self._successful.values() and not os.path.exists(
                          fullpath_new
                      ):
                          self._successful[fullpath] = fullpath_new
  
                          if insertwith == '数字序号':
                              begin += step
                      else:
                          self._failed[fullpath] = fullpath_new
                  else:
                      self._unchanged.append(fullpath)
              else:
                  self._failed[fullpath] = fullpath_new
  
      def __regex(self):
          spinf = self.stdict['spinf']
          repl = self.stdict['repl']
          pattern = self.stdict['pattern']
          count = self.stdict['count']
  
          for fullpath in self.__allfile():
              folder = os.path.dirname(fullpath)
              filename, ext = os.path.splitext(os.path.basename(fullpath))
  
              if spinf == '不含扩展名':
                  filename = re.sub(fr'{pattern}', repl, filename, count=count)
  
              elif spinf == '仅限扩展名':
                  ext = re.sub(fr'{pattern}', repl, ext, count=count)
  
              elif spinf == '全部：独立':
                  filename = re.sub(fr'{pattern}', repl, filename, count=count)
                  ext = re.sub(fr'{pattern}', repl, ext, count=count)
  
              elif spinf == '全部：整体':
                  filename, ext = filename + ext, ''
                  filename = re.sub(fr'{pattern}', repl, filename, count=count)
  
              fullpath_new = os.path.join(folder, filename + ext)
  
              if (set(filename + ext) != '.') and (
                  len(fullpath_new) <= self.MAX_NAME
              ):
                  if fullpath != fullpath_new:
                      if fullpath_new not in self._successful.values() and not os.path.exists(
                          fullpath_new
                      ):
                          self._successful[fullpath] = fullpath_new
                      else:
                          self._failed[fullpath] = fullpath_new
                  else:
                      self._unchanged.append(fullpath)
              else:
                  self._failed[fullpath] = fullpath_new
  
      def preview(self):
          '''
          预览任务执行结果。
          :return: list，成功、失败、无变化 列表。
          '''
          if not self._PREVIEWED:
              head = self.stdict['head']
              if head == 'repl':
                  self.__repl()
              elif head == 'rrepl':
                  self.__rrepl()
              elif head == 'insert':
                  self.__ins()
              elif head == 'regex':
                  self.__regex()
              self._PREVIEWED = True
          return self._successful, self._failed, self._unchanged
  
      def start(self):
          '''
          根据预览生成的列表执行重命名任务。
          :return: list，成功、失败、无变化 列表。
          '''
          if not self._PREVIEWED:
              self.preview()
          if not self.RENAMED:
              self.__rename()
          return self._successful, self._failed, self._unchanged
  
  
  if __name__ == '__main__':
      exit('请以模块方式调用。')
  