//------------------------------------------------------------------------------
// Copyright (c) 2011-2012 by European Organization for Nuclear Research (CERN)
// Author: Lukasz Janyst <ljanyst@cern.ch>
//------------------------------------------------------------------------------
// XRootD is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// XRootD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with XRootD.  If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#ifndef __XRD_CL_STATUS_HH__
#define __XRD_CL_STATUS_HH__

#include <cstdint>
#include <cerrno>
#include <sstream>

namespace XrdCl
{
  //----------------------------------------------------------------------------
  // Constants
  //----------------------------------------------------------------------------
  const uint16_t stOK    = 0x0000;  //!< Everything went OK
  const uint16_t stError = 0x0001;  //!< An error occurred that could potentially be retried
  const uint16_t stFatal = 0x0003;  //!< Fatal error, it's still an error

  //----------------------------------------------------------------------------
  // Additional info for the stOK status
  //----------------------------------------------------------------------------
  const uint16_t suDone                  = 0;
  const uint16_t suContinue              = 1;
  const uint16_t suRetry                 = 2;
  const uint16_t suPartial               = 3;
  const uint16_t suAlreadyDone           = 4;
  const uint16_t suNotStarted            = 5;

  //----------------------------------------------------------------------------
  // Generic errors
  //----------------------------------------------------------------------------
  const uint16_t errNone                 = 0; //!< No error
  const uint16_t errRetry                = 1; //!< Try again for whatever reason
  const uint16_t errUnknown              = 2; //!< Unknown error
  const uint16_t errInvalidOp            = 3; //!< The operation cannot be performed in the
                                              //!< given circumstances
  const uint16_t errFcntl                = 4; //!< failed manipulate file descriptor
  const uint16_t errPoll                 = 5; //!< error while polling descriptors
  const uint16_t errConfig               = 6; //!< System misconfigured
  const uint16_t errInternal             = 7; //!< Internal error
  const uint16_t errUnknownCommand       = 8;
  const uint16_t errInvalidArgs          = 9;
  const uint16_t errInProgress           = 10;
  const uint16_t errUninitialized        = 11;
  const uint16_t errOSError              = 12;
  const uint16_t errNotSupported         = 13;
  const uint16_t errDataError            = 14; //!< data is corrupted
  const uint16_t errNotImplemented       = 15; //!< Operation is not implemented
  const uint16_t errNoMoreReplicas       = 16; //!< No more replicas to try
  const uint16_t errPipelineFailed       = 17; //!< Pipeline failed and operation couldn't be executed

  //----------------------------------------------------------------------------
  // Socket related errors
  //----------------------------------------------------------------------------
  const uint16_t errInvalidAddr          = 101;
  const uint16_t errSocketError          = 102;
  const uint16_t errSocketTimeout        = 103;
  const uint16_t errSocketDisconnected   = 104;
  const uint16_t errPollerError          = 105;
  const uint16_t errSocketOptError       = 106;
  const uint16_t errStreamDisconnect     = 107;
  const uint16_t errConnectionError      = 108;
  const uint16_t errInvalidSession       = 109;
  const uint16_t errTlsError             = 110;

  //----------------------------------------------------------------------------
  // Post Master related errors
  //----------------------------------------------------------------------------
  const uint16_t errInvalidMessage       = 201;
  const uint16_t errHandShakeFailed      = 202;
  const uint16_t errLoginFailed          = 203;
  const uint16_t errAuthFailed           = 204;
  const uint16_t errQueryNotSupported    = 205;
  const uint16_t errOperationExpired     = 206;
  const uint16_t errOperationInterrupted = 207;
  const uint16_t errThresholdExceeded    = 208;

  //----------------------------------------------------------------------------
  // XRootD related errors
  //----------------------------------------------------------------------------
  const uint16_t errNoMoreFreeSIDs       = 301;
  const uint16_t errInvalidRedirectURL   = 302;
  const uint16_t errInvalidResponse      = 303;
  const uint16_t errNotFound             = 304;
  const uint16_t errCheckSumError        = 305;
  const uint16_t errRedirectLimit        = 306;
  const uint16_t errCorruptedHeader      = 307;

  const uint16_t errErrorResponse        = 400;
  const uint16_t errRedirect             = 401;

  const uint16_t errResponseNegative     = 500; //!< Query response was negative

  //----------------------------------------------------------------------------
  //! Procedure execution status
  //----------------------------------------------------------------------------
  struct Status
  {
    //--------------------------------------------------------------------------
    //! Constructor
    //--------------------------------------------------------------------------
    Status( uint16_t st = stOK, uint16_t cod = errNone, uint32_t errN = 0 ):
      status(st), code(cod), errNo( errN ) {}

    bool IsError() const { return status & stError; }           //!< Error
    bool IsFatal() const { return (status&0x0002) & stFatal; }  //!< Fatal error
    bool IsOK()    const { return status == stOK; }             //!< We're fine

    //--------------------------------------------------------------------------
    //! Get the status code that may be returned to the shell
    //--------------------------------------------------------------------------
    int GetShellCode() const
    {
      if( IsOK() )
        return 0;
      return (code/100)+50;
    }

    inline static bool IsSocketError( uint16_t code )
    {
      return int( code / 100 ) == 1;
    }

    //--------------------------------------------------------------------------
    //! Create a string representation
    //--------------------------------------------------------------------------
    std::string ToString() const;

    uint16_t status;     //!< Status of the execution
    uint16_t code;       //!< Error type, or additional hints on what to do
    uint32_t errNo;      //!< Errno, if any
  };
}

#endif // __XRD_CL_STATUS_HH__
