########################################################################
# $HeadURL $
# File: ReTransfer.py
# Author: Krzysztof.Ciba@NOSPAMgmail.com
# Date: 2013/04/02 14:24:21
########################################################################
""" :mod: ReTransfer

    ================


    .. module: ReTransfer

    :synopsis: ReTransfer Operation handler

    .. moduleauthor:: Krzysztof.Ciba@NOSPAMgmail.com

    ReTransfer Operation handler
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

__RCSID__ = "$Id $"

# #
# @file ReTransfer.py
# @author Krzysztof.Ciba@NOSPAMgmail.com
# @date 2013/04/02 14:24:31
# @brief Definition of ReTransfer class.

# # imports
from DIRAC import S_OK, S_ERROR
from DIRAC.FrameworkSystem.Client.MonitoringClient import gMonitor
from DIRAC.DataManagementSystem.Agent.RequestOperations.DMSRequestOperationsBase import DMSRequestOperationsBase
from DIRAC.Resources.Storage.StorageElement import StorageElement

from DIRAC.MonitoringSystem.Client.MonitoringReporter import MonitoringReporter

########################################################################


class ReTransfer(DMSRequestOperationsBase):
  """
  .. class:: ReTransfer


  online ReTransfer operation handler

  :param self: self reference
  :param ~DIRAC.RequestManagementSystem.Client.Operation.Operation operation: Operation instance
  :param str csPath: CS path for this handler

  """

  def __init__(self, operation=None, csPath=None):
    """c'tor

    """
    # # base class ctor
    DMSRequestOperationsBase.__init__(self, operation, csPath)

  def __call__(self):
    """ reTransfer operation execution """

    # The flag  'rmsMonitoring' is set by the RequestTask and is False by default.
    # Here we use 'createRMSRecord' to create the ES record which is defined inside OperationHandlerBase.
    if self.rmsMonitoring:
      self.rmsMonitoringReporter = MonitoringReporter(monitoringType="RMSMonitoring")
    else:
      # # gMonitor stuff
      gMonitor.registerActivity("FileReTransferAtt", "File retransfers attempted",
                                "RequestExecutingAgent", "Files/min", gMonitor.OP_SUM)
      gMonitor.registerActivity("FileReTransferOK", "File retransfers successful",
                                "RequestExecutingAgent", "Files/min", gMonitor.OP_SUM)
      gMonitor.registerActivity("FileReTransferFail", "File retransfers failed",
                                "RequestExecutingAgent", "Files/min", gMonitor.OP_SUM)

    # # list of targetSEs
    targetSEs = self.operation.targetSEList
    # # check targetSEs for removal
    targetSE = targetSEs[0]
    bannedTargets = self.checkSEsRSS(targetSE)
    if not bannedTargets['OK']:
      if self.rmsMonitoring:
        for status in ["Attempted", "Failed"]:
          self.rmsMonitoringReporter.addRecord(
              self.createRMSRecord(status, len(self.operation))
          )
        self.rmsMonitoringReporter.commit()
      else:
        gMonitor.addMark("FileReTransferAtt")
        gMonitor.addMark("FileReTransferFail")
      return bannedTargets

    if bannedTargets['Value']:
      return S_OK("%s targets are banned for writing" % ",".join(bannedTargets['Value']))

    # # get waiting files
    waitingFiles = self.getWaitingFilesList()
    # # prepare waiting files
    toRetransfer = dict([(opFile.PFN, opFile) for opFile in waitingFiles])

    if self.rmsMonitoring:
      self.rmsMonitoringReporter.addRecord(
          self.createRMSRecord("Attempted", len(toRetransfer))
      )
    else:
      gMonitor.addMark("FileReTransferAtt", len(toRetransfer))

    if len(targetSEs) != 1:
      error = "only one TargetSE allowed, got %d" % len(targetSEs)
      for opFile in toRetransfer.values():
        opFile.Error = error
        opFile.Status = "Failed"
      self.operation.Error = error

      if self.rmsMonitoring:
        self.rmsMonitoringReporter.addRecord(
            self.createRMSRecord("Failed", len(toRetransfer))
        )
        self.rmsMonitoringReporter.commit()
      else:
        gMonitor.addMark("FileReTransferFail", len(toRetransfer))

      return S_ERROR(error)

    se = StorageElement(targetSE)
    for opFile in toRetransfer.values():

      reTransfer = se.retransferOnlineFile(opFile.LFN)
      if not reTransfer["OK"]:
        opFile.Error = reTransfer["Message"]
        self.log.error("Retransfer failed", opFile.Error)

        if self.rmsMonitoring:
          self.rmsMonitoringReporter.addRecord(
              self.createRMSRecord("Failed", 1)
          )
        else:
          gMonitor.addMark("FileReTransferFail", 1)

        continue
      reTransfer = reTransfer["Value"]
      if opFile.LFN in reTransfer["Failed"]:
        opFile.Error = reTransfer["Failed"][opFile.LFN]
        self.log.error("Retransfer failed", opFile.Error)

        if self.rmsMonitoring:
          self.rmsMonitoringReporter.addRecord(
              self.createRMSRecord("Failed", 1)
          )
        else:
          gMonitor.addMark("FileReTransferFail", 1)

        continue
      opFile.Status = "Done"
      self.log.info("%s retransfer done" % opFile.LFN)

      if self.rmsMonitoring:
        self.rmsMonitoringReporter.addRecord(
            self.createRMSRecord("Successful", 1)
        )
      else:
        gMonitor.addMark("FileReTransferOK", 1)

    if self.rmsMonitoring:
      self.rmsMonitoringReporter.commit()

    return S_OK()
