/* $Id: asn1_aoc.c,v 1.2 1999/04/26 22:11:53 akool Exp $
 *
 * ISDN accounting for isdn4linux. (ASN.1 parser)
 *
 * Copyright 1995, 1999 by Andreas Kool (akool@isdn4linux.de)
 *
 * ASN.1 parser written by Kai Germaschewski <kai@thphy.uni-duesseldorf.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Log: asn1_aoc.c,v $
 * Revision 1.2  1999/04/26 22:11:53  akool
 * isdnlog Version 3.21
 *
 *  - CVS headers added to the asn* files
 *  - repaired the "4.CI" message directly on CONNECT
 *  - HANGUP message extended (CI's and EH's shown)
 *  - reactivated the OVERLOAD message
 *  - rate-at.dat extended
 *  - fixes from Michael Reinelt
 *
 *
 * Revision 0.1  1999/04/25 20:00.00  akool
 * Initial revision
 *
 */


#include "asn1.h"

ELEMENT_1(ParseARGAOCDCurrency, Aoc, );
ELEMENT_1(ParseARGAOCDChargingUnit, Aoc, );
ELEMENT_1(ParseARGAOCECurrency, Aoc, );
ELEMENT_1(ParseARGAOCEChargingUnit, Aoc, );

ELEMENT_1(ParseAOCDCurrencyInfo, Aoc, );
ELEMENT_1(ParseAOCDSpecificCurrency, Aoc, );
ELEMENT_1(ParseAOCDChargingUnitInfo, Aoc, );
ELEMENT_1(ParseAOCDSpecificChargingUnits, Aoc, );
ELEMENT_1(ParseRecordedCurrency, Aoc, );
ELEMENT_1(ParseRecordedUnitsList, Aoc, );
ELEMENT_1(ParseTypeOfChargingInfo, int, );
ELEMENT_1(ParseRecordedUnits, Aoc, );
ELEMENT_1(ParseRecordedUnitsChoice, Aoc, );
ELEMENT_1(ParseAOCDBillingId, int, );
ELEMENT_1(ParseAOCECurrencyInfo, Aoc, );
ELEMENT_1(ParseAOCECurrencyInfoChoice, Aoc, );
ELEMENT_1(ParseAOCESpecificCurrency, Aoc, );
ELEMENT_1(ParseAOCEChargingUnitInfo, Aoc, );
ELEMENT_1(ParseAOCEChargingUnitInfoChoice, Aoc, );
ELEMENT_1(ParseAOCESpecificChargingUnits, Aoc, );
ELEMENT_1(ParseAOCEBillingId, int, );
ELEMENT_1(ParseCurrency, char, msg);
ELEMENT_1(ParseAmount, Aoc, aoc);
ELEMENT_1(ParseCurrencyAmount, int, );
ELEMENT_1(ParseMultiplier, int, );
ELEMENT_1(ParseTypeOfUnit, int, );
ELEMENT_1(ParseNumberOfUnits, int, );
ELEMENT_1(ParseChargingAssociation, char, );
ELEMENT_1(ParseChargeIdentifier, int, );

char* XTypeOfChargingInfo[] = {
  "subTotal",
  "total",
};

const int NTypeOfChargingInfo = 2;

char* AOCDBillingId[] = {
  "normalCharging",
  "reverseCharging",
  "creditCardCharging",
};

const int NAOCDBillingId = 3;

char* AOCEBillingId[] = {
  "normalCharging",
  "reverseCharging",
  "creditCardCharging",
  "callForwardingUnconditional",
  "callForwardingBusy",
  "callForwardingNoReply",
  "callDeflection",
  "callTransfer",
};

const int NAOCEBillingId = 8;

float XMultiplier[] = {
  0.001,
  0.01,
  0.1,
  1,
  10,
  100,
  1000,
};

const int NMultiplier = 7;

// ---------------------------------------

ELEMENT_1(ParseARGAOCDCurrency, Aoc, aoc)
{
  char tmp[255];

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseARGAOCDCurrency");

  aoc->type = 33; // AOCDCurrency
  if (ParseAOCDCurrencyInfo(el, ASN1_NOT_TAGGED, aoc)) {
    ;
  } else if (ParseNull(el, ASN1_NOT_TAGGED)) {
    aoc->amount = -1; // chargeNotAvailable
    strcpy(aoc->msg, "chargeNotAvailable");
    strcpy(aoc->currency, "");
  } else {
    return 0;
  }

  sprintf(tmp, "AOC-D: %f %s %s\n",
	  aoc->amount*aoc->multiplier, aoc->currency, aoc->msg);
  strcpy(aoc->msg, tmp);
  print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", aoc->msg);

  return 1;
}

ELEMENT_1(ParseARGAOCDChargingUnit, Aoc, aoc)
{
  char tmp[255];

  MY_DEBUG("ParseARGAOCDChargingUnit");

  aoc->type = 34; // AOCDChargingUnit
  if (ParseAOCDChargingUnitInfo(el, ASN1_NOT_TAGGED, aoc)) {
    ;
  } else if (ParseNull(el, ASN1_NOT_TAGGED)) {
    aoc->amount = 1; // chargeNotAvailable
    strcpy(aoc->msg, "chargeNotAvailable");
  } else {
    return 0;
  }

  sprintf(tmp, "AOC-D: %d EH, %s", aoc->amount, aoc->msg);
  strcpy(aoc->msg, tmp);
  print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", aoc->msg);

  return 1;
}

ELEMENT_1(ParseARGAOCECurrency, Aoc, aoc)
{
  char tmp[255];

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseARGAOCECurrency");

  aoc->type = 35; // AOCECurrency
  if (ParseAOCECurrencyInfo(el, ASN1_NOT_TAGGED, aoc)) {
    ;
  } else if (ParseNull(el, ASN1_NOT_TAGGED)) {
    aoc->amount = -1; // chargeNotAvailable
    strcpy(aoc->msg, "chargeNotAvailable");
    strcpy(aoc->currency, "");
  } else {
    return 0;
  }

  sprintf(tmp, "AOC-D: %f %s %s\n",
	  aoc->amount*aoc->multiplier, aoc->currency, aoc->msg);
  strcpy(aoc->msg, tmp);
  print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", aoc->msg);

  return 1;
}

ELEMENT_1(ParseARGAOCEChargingUnit, Aoc, aoc)
{
  char tmp[255];

  MY_DEBUG("ParseARGAOCEChargingUnit");

  aoc->type = 36; // AOCEChargingUnit
  if (ParseAOCEChargingUnitInfo(el, ASN1_NOT_TAGGED, aoc)) {
    ;
  } else if (ParseNull(el, ASN1_NOT_TAGGED)) {
    aoc->amount = -1; // chargeNotAvailable
    strcpy(aoc->msg, "chargeNotAvailable");
  } else {
    return 0;
  }

  sprintf(tmp, "AOC-E: %d EH, %s", aoc->amount, aoc->msg);
  strcpy(aoc->msg, tmp);
  print_msg(PRT_DEBUG_DECODE, " DEBUG> %s\n", aoc->msg);

  return 1;
}

ELEMENT_1(ParseAOCDCurrencyInfo, Aoc, aoc)
{
 MY_DEBUG("ParseAOCDCurrencyInfo");

  if (ParseAOCDSpecificCurrency(el, tag, aoc)) {
    ;
  } else if (ParseNull(el, 1)) {
    aoc->amount = 0; // freeOfCharge
    strcpy(aoc->msg, "freeOfCharge");
  } else {
    return 0;
  }

  return 1;
}

ELEMENT_1(ParseAOCDSpecificCurrency, Aoc, aoc)
{
  int billingId = -1;

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseAOCDSpecificCurrency");

  SEQ_TAGGED_1(ParseRecordedCurrency, 1, aoc);
  SEQ_TAGGED_1(ParseTypeOfChargingInfo, 2, &aoc->type_of_charging_info);
  SEQOPT_TAGGED_1(ParseAOCDBillingId, 3, &billingId);

  sprintf(aoc->msg, "typeOfChargingInfo = %s, billingId = %s",
	  XTypeOfChargingInfo[aoc->type_of_charging_info],
	  (billingId==-1)?"-":AOCDBillingId[billingId]);

  return 1;
}

ELEMENT_1(ParseAOCDChargingUnitInfo, Aoc, aoc)
{
  MY_DEBUG("ParseAOCDChargingUnitInfo");

  if (ParseAOCDSpecificChargingUnits(el, tag, aoc)) {
    ;
  } else if (ParseNull(el, 1)) {
    aoc->amount = 0; // freeOfCharge
    strcpy(aoc->msg, "freeOfCharge");
  } else {
    return 0;
  }

  return 1;
}

ELEMENT_1(ParseAOCDSpecificChargingUnits, Aoc, aoc)
{
  int billingId = -1;

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseAOCDSpecificChargingUnits");

  SEQ_TAGGED_1(ParseRecordedUnitsList, 1, aoc);
  SEQ_TAGGED_1(ParseTypeOfChargingInfo, 2, &aoc->type_of_charging_info);
  SEQOPT_TAGGED_1(ParseAOCDBillingId, 3, &billingId);

  sprintf(aoc->msg, "typeOfChargingInfo = %s, billingId = %s",
	  XTypeOfChargingInfo[aoc->type_of_charging_info],
	  (billingId==-1)?"-":AOCDBillingId[billingId]);

  return 1;
}

ELEMENT_1(ParseRecordedCurrency, Aoc, aoc)
{
  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseRecordedCurrency");

  SEQ_TAGGED_1(ParseCurrency, 1, aoc->currency);
  SEQ_TAGGED_1(ParseAmount, 2, aoc);

  return 1;
}

ELEMENT_1(ParseRecordedUnitsList, Aoc, aoc)
{
  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseRecordedUnitsList");

  aoc->amount = 0;
  while (elnr < el.length) {
    SEQ_NOT_TAGGED_1(ParseRecordedUnits, aoc);
  }

  return 1;
}

ELEMENT_1(ParseTypeOfChargingInfo, int, typeOfChargingInfo)
{
  MY_DEBUG("ParseTypeOfChargingInfo");

  if (!ParseEnum(el, tag, typeOfChargingInfo)) return 0;

  if ((*typeOfChargingInfo < 0) || (*typeOfChargingInfo > NTypeOfChargingInfo))
    return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> typeOfChargingInfo = %s\n",
	    XTypeOfChargingInfo[*typeOfChargingInfo]);
  return 1;
}

ELEMENT_1(ParseRecordedUnits, Aoc, aoc)
{
  int typeOfUnit = -1;

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseRecordedUnits");

  SEQ_NOT_TAGGED_1(ParseRecordedUnitsChoice, aoc);
  SEQOPT_NOT_TAGGED_1(ParseTypeOfUnit, &typeOfUnit);

  if (typeOfUnit != -1) {
    sprintf(aoc->msg, "typeOfUnit = %d", typeOfUnit);
  }
  return 1;
}

ELEMENT_1(ParseRecordedUnitsChoice, Aoc, aoc)
{
  int eh;

  MY_DEBUG("ParseRecordedUnitsChoice");

  if (ParseNumberOfUnits(el, ASN1_NOT_TAGGED, &eh)) {
    aoc->amount += eh;
  } else if (ParseNull(el, ASN1_NOT_TAGGED)) {
    aoc->amount = -1; // notAvailable
  } else {
    return 0;
  }
  return 1;
}

ELEMENT_1(ParseAOCDBillingId, int, billingId)
{
  MY_DEBUG("ParseAOCDBillingId");

  if (!ParseEnum(el, tag, billingId)) return 0;

  if ((*billingId < 0) || (*billingId > NAOCDBillingId))
    return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> AOCDBillingId = %s\n",
	    AOCDBillingId[*billingId]);
  return 1;
}

ELEMENT_1(ParseAOCECurrencyInfo, Aoc, aoc)
{
  char msg[21] = "";

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseARGAOCECurrencyInfo");

  SEQ_NOT_TAGGED_1(ParseAOCECurrencyInfoChoice, aoc);
  SEQOPT_NOT_TAGGED_1(ParseChargingAssociation, msg);

  if (strcmp(msg, "") != 0) {
    strcat(aoc->msg, " chargingAssociation: ");
    strcat(aoc->msg, msg);
  }

  return 1;
}

ELEMENT_1(ParseAOCECurrencyInfoChoice, Aoc, aoc)
{
 MY_DEBUG("ParseAOCECurrencyInfoChoice");

  if (ParseAOCESpecificCurrency(el, tag, aoc)) {
    ;
  } else if (ParseNull(el, 1)) {
    aoc->amount = 0; // freeOfCharge
    strcpy(aoc->msg, "freeOfCharge");
  } else {
    return 0;
  }

  return 1;
}

ELEMENT_1(ParseAOCESpecificCurrency, Aoc, aoc)
{
  int billingId = -1;

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseAOCESpecificCurrency");

  SEQ_TAGGED_1(ParseRecordedCurrency, 1, aoc);
  SEQOPT_TAGGED_1(ParseAOCEBillingId, 2, &billingId);

  if (billingId != -1) {
    strcpy(aoc->msg, "billingId = ");
    strcat(aoc->msg, AOCEBillingId[billingId]);
  } else {
    strcpy(aoc->msg, "");
  }
  return 1;
}

ELEMENT_1(ParseAOCEChargingUnitInfo, Aoc, aoc)
{
  char msg[21] = "";

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseAOCEChargingUnitInfo");

  SEQ_NOT_TAGGED_1(ParseAOCEChargingUnitInfoChoice, aoc);
  SEQOPT_NOT_TAGGED_1(ParseChargingAssociation, msg);

  if (strcmp(msg, "") != 0) {
    strcat(aoc->msg, " ChargingAssociation = ");
    strcat(aoc->msg, msg);
  }

  return 1;
}

ELEMENT_1(ParseAOCEChargingUnitInfoChoice, Aoc, aoc)
{
  MY_DEBUG("ParseAOCEChargingUnitInfoChoice");

  if (ParseAOCESpecificChargingUnits(el, tag, aoc)) {
    ;
  } else if (ParseNull(el, 1)) {
    aoc->amount = 0; // freeOfCharge
    strcpy(aoc->msg, "freeOfCharge");
  } else {
    return 0;
  }
  return 1;
}

ELEMENT_1(ParseAOCESpecificChargingUnits, Aoc, aoc)
{
  int billingId = -1;

  CHECK_TAG(ASN1_TAG_SEQUENCE);
  MY_DEBUG("ParseAOCESpecificChargingUnits");

  SEQ_TAGGED_1(ParseRecordedUnitsList, 1, aoc);
  SEQOPT_TAGGED_1(ParseAOCEBillingId, 2, &billingId);

  if (billingId != -1) {
    strcpy(aoc->msg, "billingId = ");
    strcat(aoc->msg, AOCEBillingId[billingId]);
  } else {
    strcpy(aoc->msg, "");
  }

  return 1;
}


ELEMENT_1(ParseAOCEBillingId, int, billingId)
{
  MY_DEBUG("ParseAOCEBillingId");

  if (!ParseEnum(el, tag, billingId)) return 0;

  if ((*billingId < 0) || (*billingId > NAOCEBillingId))
    return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> billingId = %s\n",
	    AOCEBillingId[*billingId]);
  return 1;
}

ELEMENT_1(ParseCurrency, char, msg)
{
  MY_DEBUG("ParseCurrency");

  if (!ParseIA5String(el, tag, msg)) return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> Currency = %s\n",
	    msg);

  return 1;
}

ELEMENT_1(ParseAmount, Aoc, aoc)
{
  int multiplier;

  CHECK_TAG(ASN1_TAG_SEQUENCE);

  MY_DEBUG("ParseAmount");

  SEQ_TAGGED_1(ParseCurrencyAmount, 1, &aoc->amount);
  SEQ_TAGGED_1(ParseMultiplier, 2, &multiplier);

  aoc->multiplier = XMultiplier[multiplier];

  print_msg(PRT_DEBUG_DECODE, " DEBUG> Amount = %d * %f\n",
	    aoc->amount, aoc->multiplier);

  return 1;
}

ELEMENT_1(ParseCurrencyAmount, int, amount)
{
  MY_DEBUG("ParseCurrencyAmount");

  if (!ParseInteger(el, tag, amount)) return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> CurrencyAmount = %d\n",
	    *amount);

  return 1;
}

ELEMENT_1(ParseMultiplier, int, multiplier)
{
  MY_DEBUG("ParseMultiplier");

  if (!ParseEnum(el, tag, multiplier)) return 0;

  if ((*multiplier < 0) || (*multiplier > NMultiplier))
    return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> Multiplier = %f\n",
	    XMultiplier[*multiplier]);

  return 1;
}

ELEMENT_1(ParseTypeOfUnit, int, typeOfUnit)
{
  MY_DEBUG("ParseTypeOfUnit");

  if (!ParseInteger(el, tag, typeOfUnit)) return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> typeOfUnit = %d\n",
	    *typeOfUnit);

  return 1;
}

ELEMENT_1(ParseNumberOfUnits, int, numberOfUnits)
{
  MY_DEBUG("ParseNumberOfUnits");

  if (!ParseInteger(el, tag, numberOfUnits)) return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> numberOfUnits = %d\n",
	    *numberOfUnits);

  return 1;
}

ELEMENT_1(ParseChargingAssociation, char, s)
{
  int chargeIdentifier;

  MY_DEBUG("ParseChargingAssociation");

  if ((el.tag &~ 0xa0) == 0) {
    if (!ParsePartyNumber(el.content.elements[0], ASN1_NOT_TAGGED, s))
      return 0;
  } else {
    if (!ParseChargeIdentifier(el, ASN1_NOT_TAGGED, &chargeIdentifier)) {
      return 0;
    } else {
      sprintf(s, "%d", chargeIdentifier);
    }
  }
  return 1;
}

ELEMENT_1(ParseChargeIdentifier, int, chargeIdentifier)
{
  MY_DEBUG("ParseChargeIdentifier");

  if (!ParseInteger(el, tag, chargeIdentifier)) return 0;

  print_msg(PRT_DEBUG_DECODE, " DEBUG> chargeIdentifier = %d\n",
	    *chargeIdentifier);

  return 1;
}
