//______________________________________________________________________________
//   |       |
//   | knipp |           Knipp Medien und Kommunikation GmbH
//    -------
//
//
//     Knipp RRI Toolkit
//
//
//     Copyright (C) 2005 by Knipp Medien und Kommunikation GmbH
//
//     This library 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 2.1 
//     of the License, or any later version.
// 
//     This library 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 Lesser General Public License for more details.
//
//     You should have received a copy of the GNU Lesser General
//     Public License along with this library; if not, write to the 
//     Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
//     Boston, MA 02111-1307 USA 
//
//
//     initial author:    Klaus Malorny
//
//     version:           1.4 (15127), 2011/06/03 14:52:49
//                        $Revision: 15117 $ 
//                        $Date: 2011-05-30 16:46:11 +0200 (Mon, 30 May 2011) $
//                        $Author: Klaus.Malorny $
//

package de.knipp.rritoolkit.response;

import java.util.EnumSet;
import java.util.List;
import java.util.ArrayList;


/**
 *  enumeration that contains all known DENIC error codes as well as some
 *  generalized error values. The values also contain some pseudo codes that 
 *  can be used to cover certain groups of error codes.
 *  
 *  @version  $Revision: 15117 $
 *  @author   Klaus Malorny
 */

public enum ErrorType
{  
  // the comments are taken from the official DENIC documentation.
  // Errors that no longer occur in the documentation are marked as deprecated

  /** Request was processed in test environment - not valid in real world */

  InfoTestEnvironment ("13000000011"),


  /** Information about the used access quota */

  InfoUsedAccessQuota ("13000000022"),
  

  /** Value for "Zone-c" has been replaced by "DENIC-1000100-OPS" */

  InfoZoneContactReplaced ("13300062713"),


  /** AuthInfo deleted */

  InfoAuthInfoDeleted ("13300088725"),


  /** AuthInfo letter could not be delivered */

  InfoAuthInfoLetterNotDelivered ("11300088726"),


  /** CHPROV-request received for your domain */
  
  InfoChProvReceived ("13370080023"),
  
  
  /** ACK received and processed */
  
  InfoAckProcessed ("13374080024"),
  
  
  /** Existing Authinfo2 for Domain */
  
  InfoExistingAuthInfo2 ("13391088704"),
  
  
  /** This months available "WithProvider" requests */
  
  InfoAvailWithProviderReq ("13450023807"),
  
  
  /** Domain already migrated to holder-handle */
  
  InfoDomainAlreadyHHMigrated ("13900080015"),


  /** Domain was deleted according to DENIC Legal Department */

  InfoDomainDeleteByLegalDepartment ("1635000031"),
  

  /** Warning about reaching the access quota */

  WarnUsedAccessQuota ("33000000022"),


  /** The NS entries are faulty. The status of the domain is failed */

  WarnNSEntriesFaulty ("33300102900"),


  /** Zonecheck warning */

  WarnZoneCheck ("33300102912"),


  /** Unauthorized "WithProvider = true" request */
  
  WarnUnauthorizedWithProviderReq ("36450023815"),
  

  /** Secure Entry Point flag should be set in DNSKEY */

  WarnSecureEntryPointShouldBeSet ("46000108827"),

  
  /** Concurrent write access to the same business object is prohibited */

  ErrConcurrentWrite ("53000000012"),


  /** Access quota has been exceeded */

  ErrAccessQuotaExceeded ("53000000008"),


  /** Unauthorized request */

  ErrUnauthorizedRequest ("53000020002"),


  /** Verification of signature failed */

  ErrSignatureVerificationFailed ("53000020013"),


  /** Signature of request is correct but too old */

  ErrSignatureTooOld ("53000020019"),


  /** At least one contact does not exist */

  ErrContactDoesNotExist ("53000060009"),


  /** This value cannot be deleted */

  ErrValueCannotBeDeleted ("53000080002"),


  /** The request cannot be processed because of an active CHPROV */

  ErrFailedDueActiveChProv ("53000080006"),


  /** The request cannot be processed because of an active DISPUTE */

  ErrFailedDueActiveDispute ("53000080011"),


  /** The domain has to be connected/Domain "Status" is "failed" */

  ErrDomainMustBeConnected ("53000080012"),


  /** Connection released due to time-out */

  ErrConnectionTimeout ("53100000019"),


  /** Invalid format of value for keyword "Domain" */

  ErrInvalidDomainValueFormat ("53300062003"),


  /** The value(s) for "Holder" (and/or the number of holders) does
      not match the database */

  ErrHoldersDoNotMatchDatabase ("53300062506"),


  /** Either the holder(s) or the admin-c must have a postal
      address in Germany */

  ErrGermanAddressReqForHolderOrAdmin ("53300080000"),


  /** Within a contact "Phone" is missing */

  ErrPhoneMissingInContact ("53300081400"),


  /** Within a contact "Fax" is missing */

  ErrFaxMissingInContact ("53300081500"),


  /** Within a contact "Email" is missing */

  ErrEMailMissingInContact ("53300081600"),


  /** Required glue record is missing */
  
  ErrRequiredGlueRecMissing ("53300102902"),
  
  
  /** Name server error */

  ErrZoneCheck ("53300102912"),


  /** Illegal number of name servers in domain */
  
  ErrIllegalNSNumber ("53300102920"),
  

  /** Missing mail exchange preference of DNS entry */
  
  ErrMissingMXPref ("53300103022"),
  
  
  /** Holder does not match */
  
  ErrHolderDoesNotMatch ("53350062506"),
  
  
  /** Required change provider request data is missing */
  
  ErrRequiredChProvDataMissing ("53370080005"),


  /** Access control limit reached */

  ErrAccessControlLimitReached ("56000020021"),


  /** The provided DNS data are not acceptable */

  ErrDnsDataIsNotAcceptable ("56300108812"),


  /** No order found */

  ErrNoOrderFound ("57000000022"),


  /** Text part has not been encoded properly */

  ErrTextPartNotProperlyEncoded ("58000000002"),


  /** Mail header is incomplete */

  ErrMailHeaderIsIncomplete ("58000000027"),


  /** The request has an invalid key/value pair format */

  ErrSyntaxErrorInRequest ("63000000006"),


  /** Request shows semantics error */

  ErrSemanticErrorInRequest ("63000000007"),


  /** Keyword "Action" cannot be recognized */

  ErrActionKeyUnrecognized ("63000040110"),


  /** Keyword "Version" cannot be recognized */

  ErrVersionKeyUnrecognized ("63000040410"),


  /** Keyword "Domain" cannot be recognized */

  ErrDomainKeyUnrecognized ("63000042010"),


  /** An indicated contact is invalid */

  ErrInvalidContact ("63000060003"),


  /** The value contains one or more invalid characters */

  ErrInvalidCharactersInValue ("63000060008"),


  /** The value is too long */

  ErrValueTooLong ("63000060015"),


  /** Inadmissible value for keyword "Action" */

  ErrInadmissibleActionValue ("63000060102"),


  /** Inadmissible value for keyword "Version" */

  ErrInadmissibleVersionValue ("63000060402"),


  /** Ctid */

  ErrDuplicateCtid ("63000060504"),


  /** Invalid character(s) in "Ctid" value */

  ErrInvalidCharactersInCtid ("63000060508"),


  /** Request type is missing, either keyword "Domain" or "Holder" */

  ErrActionNotAssignableToRequestType ("63000080009"),


  /** Number of failed logins exceeds allowed maximum */

  ErrTooManyFailedLogins ("63100020005"),


  /** Keyword "User" must appear once and just once */

  ErrMissingOrMultipleUserKeys ("63100040202"),


  /** Keyword "Password" must appear once and just once */

  ErrMissingOrMultiplePasswordKeys ("63100040302"),


  /** Authorization failure (value for "User" not an authorized handle
      or incorrect password) */

  ErrUserOrPasswordWrong ("63100064002"),


  /** This contact is administered by another provider */

  ErrContactMaintainedByDifferentProv ("63200020603"),


  /** Keyword "Handle" or "Domain" must appear once and just once */

  ErrMultipleHandleOrDomainKeys ("63200040602"),


  /** Keyword "Handle" cannot be recognized */

  ErrMissingHandleKey ("63200040610"),


  /** Keyword "Type" must appear once and just once */

  ErrMultipleTypeKeys ("63200040702"),


  /** Keyword "Type" cannot be recognized */

  ErrMissingTypeKey ("63200040710"),


  /** Keyword "Name" must appear once and just once */

  ErrMultipleNameKeys ("63200040802"),


  /** Keyword "Name" cannot be recognized */

  ErrMissingNameKey ("63200040810"),


  /** Keyword "Address" cannot be recognized */

  ErrMissingAddressKey ("63200041010"),


  /** Keyword "PostalCode" must appear once and just once */

  ErrMultiplePostalCodeKeys ("63200041102"),


  /** Keyword "PostalCode" cannot be recognized */

  ErrMissingPostalCodeKey ("63200041110"),


  /** Keyword "City" must appear once and just once */

  ErrMultipleCityKeys ("63200041202"),


  /** Keyword "City" cannot be recognized */

  ErrMissingCityKey ("63200041210"),


  /** Keyword "Country" must appear once and just once */

  ErrMultipleCountryCodeKeys ("63200041302"),


  /** Keyword "CountryCode" cannot be recognized */

  ErrMissingCountryCodeKey ("63200041310"),


  /** Keyword "Disclose" must appear once and just once */

  ErrMultipleDiscloseKeys ("63200041802"),


  /** Inadmissable value for keyword "Type" */

  ErrIncorrectTypeValue ("63200060702"),


  /** The value for "CountryCode" is not a valid ISO code */

  ErrIncorrectCountryCodeValue ("63200061302"),


  /** The value for "Email" has an invalid format */

  ErrIncorrectEMailValue ("63200061603"),


  /** Invalid character(s) in "Sip" value */

  ErrIncorrectSipValue ("63200061708"),


  /** Inadmissible value for keyword "Disclose" */

  ErrIncorrectDiscloseValue ("63200061802"),


  /** The value for "Phone" and/or "Fax" has an invalid format */

  ErrIncorrectPhoneOrFaxValue ("63200064103"),


  /** Required contact data are missing or invalid */

  ErrMissingOrInvalidContactData ("63200080010"),


  /** This value of "Action" is not permitted here */

  ErrInvalidActionValue ("63200080108"),


  /** Keyword "Organisation" invalid with "Type" "ORG" */

  ErrRoleMustBePersonOrRole ("63200080900"),


  /** The value of "Type" cannot be changed with an UPDATE */

  ErrTypeMustNotBeChanged ("63220080701"),


  /** The value of "Name" cannot be changed with an UPDATE */

  ErrNameMustNotBeChanged ("63220080801"),


  /** This Domain is administered by another provider */

  ErrDomainMaintainedByDifferentProv ("63300022003"),


  /** Keyword "Domain-ace" must appear once and just once */

  ErrMultipleDomainACEKeys ("63300042102"),


  /** Keyword "Admin-c" cannot be recognized */

  ErrMissingAdminCKey ("63300042610"),


  /** More than five occurrences of keyword "Nsentry" */

  ErrMoreThanFiveNSEntryKeys ("63300043003"),


  /** DNS information is missing */

  ErrMissingDNSInformation ("63300043100"),


  /** Contact occurs more than once in the same role */

  ErrDuplicateRoleForContact ("63300060005"),


  /** Invalid value for "Domain" */
  
  ErrInvalidDomainValue ("63300062007"),
  
  
  /** This domain doesn't exist */

  ErrDomainDoesNotExist ("63300062009"),


  /** Mismatch between values for "Domain-ace" and "Domain" */

  ErrDomainACEMismatch ("63300062106"),


  /** Duplicate value(s) for "Nserver" */

  ErrDuplicateNServerValue ("63300062905"),


  /** Preference values for MX-RR are outside of range (0-999) */

  ErrInvalidMXPrefValue ("63300063002"),


  /** Incorrect value(s) for "Nsentry" (not IN A or IN MX entries) */

  ErrInvalidNSEntryType ("63300063003"),


  /** Duplicate nsentry record is present */

  ErrDuplicateNSEntry ("63300063005"),


  /** Mismatch(es) between "Nsentry" value(s) and "Domain" */

  ErrInvalidNSEntryOwner ("63300063006"),


  /** At least 2 MX entries have the identical preference */

  ErrDuplicateMXPrefValue ("63300063016"),


  /** Unknown dnsentry type */

  ErrUnknownDNSType ("63300063102"),


  /** Illegal dnsentry type */

  ErrInvalidDNSType ("63300063103"),


  /** Required domain data is missing */

  ErrInvalidOrMissingDomainData ("63300080010"),


  /** Too many contacts are indicated */

  ErrTooManyContactsForRole ("63300080013"),


  /** Contact with wrong type */

  ErrWrongContactTypeForRole ("63300080700"),


  /** An IN-A record must exist */

  ErrARecordRequired ("63300083005"),


  /** The IP is invalid in at least one glue record */

  ErrInvalidGlueIPAddress ("63300102913"),


  /** Domain already exists */

  ErrDomainExists ("63310062004"),


  /** Incorrect format value for keyword "Domain"
      @deprecated does no longer occur in the official list */

  ErrInadmissibleDomainValue ("63310062007"),

  
  /** This domain doesn't exist */
  
  ErrDomainToDeleteDoesNotExist ("63350062009"),

  
  /** Keyword "Disconnect" must appear once and just once */

  ErrMultipleDisconnectKeys ("63360043403"),


  /** Inadmissible value for keyword "Disconnect" */

  ErrInadmissibleDisconnectValue ("63360063402"),


  /** AuthInfo does not match */

  ErrAuthInfoDoesNotMatch ("63370088701"),


  /** Keyword "AuthInfoHash" must appear once and just once */

  ErrAuthInfoHashNotExactlyOnce ("63391048502"),
  

  /** Keyword "AuthInfoExpire" can appear once and just once */
  
  ErrAuthInfoExpireNotExactlyOnce ("63391048602"),


  /** Invalid format of value for keyword "AuthInfoHash" */

  ErrInvalidAuthInfoHashValue ("63391068503"),


  /** Invalid format of value for keyword "AuthInfoExpire" */

  ErrInvalidAuthInfoExpireFormat ("63391068603"),
  

  /** Value for "AuthInfoExpire" is out of range */

  ErrAuthInfoExpireValueOutOfRange ("63391068618"),


  /** Authinfo1 already exists
      @deprecated does no longer occur in the official list */
  
  ErrAuthInfo1AlreadyExists ("63391068704"),
  

  /** Domain has Description */

  ErrDomainHasDescription ("63391082031"),


  /** Authinfo1 does not exist */
  
  ErrAuthInfo1DoesNotExist ("63392068709"),
  

  /** AuthInfo2 already exists
      @deprecated does no longer occur in the official list */

  ErrAuthInfo2AlreadyExists ("63393068074"),


  /** Recipient is unascertainable */

  ErrRecipientIsUnascertainable ("63393080000"),


  /** Keyword "WithProvider" must appear once and just once */

  ErrMultipleWithProviderKeys ("63450043802"),


  /** Keyword "Recursive" must appear once and just once */

  ErrMultipleRecursiveKeys ("63450043902"),


  /** Inadmissible value for keyword "WithProvider" */

  ErrInadmissibleWithProviderValue ("63450063802"),


  /** Inadmissible value for keyword "Recursive" */

  ErrInadmissibleRecursiveValue ("63450063902"),


  /** Inadmissible value for keyword "MsgType" */

  ErrInadmissibleMsgTypeValue ("63600063502"),


  /** Only the first message in the queue may be deleted */

  ErrNotOldestMessage ("63650063607"),


  /** MsgId does not exist */

  ErrMessageDoesNotExist ("63650063609"),


  /** Domain holder migration allows one target handle only */

  ErrMultipleTargets ("63900042502"),


  /** Zone Key flag must be set in DNSKEY */

  ErrZoneKeyFlagMustBeSet ("66000108825"),


  /** Revoke flag must not be set in DNSKEY */

  ErrRevokeFlagMustNotBeSet ("66000108826"),


  /** RSA Key modulus out of range (512-4096 bits long) */

  ErrRsaKeyModulusOutOfRange ("66000108828"),


  /** RSA Key exponent is too big (more than 128 bits long) */

  ErrRsaKeyExponentTooLarge ("66000108829"),


  /** DSA Key Size Parameter T out of range (0 - 8) */

  ErrDsaKeySizeParameterTOutOfRange ("66000108830"),


  /** DSA Key has invalid size (213+[0-8]*24 bytes) */

  ErrDsaKeySizeInvalid ("66000108831"),


  /** Invalid DNS Data (Nsentry, Dnskey) */

  ErrInvalidDnsData ("66300048905"),


  /** AAAA resource record requires corresponding A resource record */
  
  ErrAAAARequiresA ("66300063023"),


  /** "Dnskey" wrong format */

  ErrDnskeyWrongFormat ("66300068803"),


  /** Dnskey invalid */

  ErrDnskeyInvalid ("66300068807"),


  /** The maximum number of permitted logins has been reached */

  FatalTooManyLogins ("73100000005"),


  /** The request message exceeds the size limit */

  FatalRequestTooLong ("83000000000"),


  /** The encoding specified is not supported */

  FatalUnsupportedEncoding ("83000000002"),


  /** Validation of XML request against Schema failed */

  FatalXMLValidationFailed ("83000000004"),


  /** Login failed or you are not authorized */

  FatalNotLoggedIn ("83000000010"),


  /** special value: other error than the specified ones */
  
  Other,
  
  
  /** special value: no error at all */
  
  None;
  
  
  /** the pattern */
  
  private ErrorPattern pattern;

  
  
  /** the mapper */
  
  private static final ErrorMapper<ErrorType> mapper;
  
  
  
  /**
   *  class constructor
   */
  
  static
  {
    mapper = new ErrorMapper<ErrorType> ();
    
    for (ErrorType et: values ())
    {
      ErrorPattern pattern = et.pattern;
      if (pattern != null) mapper.add (pattern, et);
    }
  }
  
  
  /**
   *  constructor for special purposes
   */
  
  private ErrorType ()
  {
  }
  
  
  /**
   *  constructor, matches exactly the given error code
   *
   *  @param code                 the code
   */
  
  private ErrorType (String code)
  {
    pattern = new SimplePattern (code);
  }


  /**
   *  constructor with a pre-created pattern
   *
   *  @param thePattern           the pattern
   */
  
  private ErrorType (ErrorPattern thePattern)
  {
    pattern = thePattern;
  }

  
  
  
  /**
   *  return a collection of all detected errors
   *
   *  @param ec                     the error code
   *  @return                       the set of matching values
   */
  
  public static EnumSet<ErrorType> getErrors (ErrorCode ec)
  {
    EnumSet<ErrorType> set = EnumSet.noneOf (ErrorType.class);
    mapper.findMatches (ec, set);
    return set;
  }
  
  
  
  /**
   *  create a summary of all errors occurring in the response.
   *  If an error occurs that is not mapped to one of the enum values,
   *  a special value {@code Other} is added to returned set.
   *
   *  @param resp                   the response
   *  @return                       the set of matching values
   */
  
  public static EnumSet<ErrorType> getErrors (Response resp)
  {
    EnumSet<ErrorType> set = EnumSet.noneOf (ErrorType.class);
    boolean allFound = true;
    
    for (ResultMessage msg: resp.getResultMessages ())
    {
      allFound &= mapper.findMatches (msg, set);  // don't use && !
    }
    
    if (!allFound) set.add (Other);
    return set;
  }
  
  
  
  /**
   *  test whether any of the given error codes occur in the response. If
   *  multiple of the specified error codes exist, the first of the actual
   *  parameters is returned. If the response has result messages, but they
   *  do not match any of the parameters, a special value {@code Other}
   *  is returned. If the response has no result messages at all, 
   *  {@code None} is returned.
   *
   *  @param resp                       the response
   *  @param codes                      the error codes to test for
   *  @return                           the matching code or {@code Other}
   *                                    or {@code None}
   */
  
  public static ErrorType test (Response resp, ErrorType... codes)
  {
    List<ResultMessage> msgs = resp.getResultMessages ();
    if (msgs.isEmpty ()) return None;

    EnumSet<ErrorType> set = EnumSet.noneOf (ErrorType.class);

    for (ResultMessage msg: msgs)
      mapper.findMatches (msg, set);
    
    for (ErrorType et: codes)
      if (set.contains (et)) return et;
    
    return Other;
  }
  
  
  
  /**
   *  filter those result messages that match one of the given codes
   *
   *  @param resp                      the response
   *  @param codes                     the codes to use for filtering
   *  @return                          the list of result messages that match
   */
  
  public static List<ResultMessage> filter (Response resp, ErrorType... codes)
  {
    List<ErrorPattern> list = new ArrayList<ErrorPattern> ();
    
    for (ErrorType et: codes)
      if (et.pattern != null) list.add (et.pattern);
    
    ErrorPattern[] patterns = new ErrorPattern[list.size ()];
    list.toArray (patterns);
    
    return ErrorMapper.filter (resp.getResultMessages (), patterns);
  }
  
  
}





