using System;
using System.Text;
using System.Security.Cryptography;

namespace Wrox.ProCSharpWebServices.Chapter11.Card
{
    public enum CardTypes : short { Undefined, Visa, Master, Amex, Discovery} 

    public interface ICCard 
    {
       string CardNumber     { get;set;}
       string HolderName     { get;set;}
       string ZipCode        { get;set;}
       DateTime  ExpiryDate  { get;set;}
       CardTypes CType       { get;set;}
       
    }

    public interface ICharge  
    {
       string MerchantId   { get;set;}
       double Amount       { get;set;}
       string CurrencyName { get;set;} 
       string InvoiceRef   { get;set;}
    }

    public interface ITransactCard 
    {
        long Transact(ICharge charge, ICCard card);
        bool IsValid(ICCard card);
    }

    [Serializable]
    public sealed class SimpleCCard : ICCard  
    {
       
       public string CardNumber 
       { 
          get { return cardNumber; }
          set { cardNumber = value;}
       }
       public string HolderName 
       { 
          get { return holderName; }
          set { holderName = value;}
       }
       public string ZipCode   
       { 
          get { return zipCode;}
          set { zipCode = value;}
       }
       public DateTime  ExpiryDate 
       { 
          get { return expDt; }
          set { expDt = value;}
       }
       public CardTypes CType 
       { 
          get { return ctyp; }
          set { ctyp = value;}
       }

      
       private DateTime  expDt;       
       private CardTypes ctyp        = CardTypes.Undefined;
       private String cardNumber = null;
       private String holderName = null;
       private String zipCode    = null;
   
    } // END: class SimpleCCard
    
    [Serializable]
    public class SimpleCharge : ICharge
    {
       public string MerchantId
       {
          get { return merchantId; }
          set { merchantId = value; }
       }
       
       public double Amount     
       {
          get { return amount; }
          set { amount = value;}
       }
       
       public string CurrencyName 
       { 
         get { return curn;}  
         set { curn = value;}
       }

       public string InvoiceRef 
       {
          get { return invref; }
          set { invref = value;}
           
       }

       private String merchantId = null;
       private double amount = 0;
       private string invref = null;
       private string curn = null;
    } // END: SimpleCharge


    public interface ISecureBag
    {
        RSA       Key         { get; set;}
    }

    
    [Serializable]
    public class SecureBag : ISecureBag
    {

       public virtual RSA  Key 
       {
          get
          {
             CheckPubKey();
              
             return rsa;   
          }
          set
          {
             rsa = value;
             pubxml = rsa.ToXmlString(false); // public key portions
          }

       }
       
       protected string DecryptString(byte[] encr)
       {
           if(rsa == null)
              throw new ApplicationException("No Private key defined");

           string ret = null;
           if(encr != null)
           {
               byte [] decrp = ((RSACryptoServiceProvider) rsa).Decrypt(encr, false);
               ret = (new ASCIIEncoding()).GetString(decrp);
           }
           return ret;
       }
       
       protected  byte[] EncryptString(string val)
       {
            CheckPubKey();
            return ((RSACryptoServiceProvider) rsa).Encrypt((new ASCIIEncoding()).GetBytes(val), false);

       }
       protected void CheckPubKey()
       {
          if(rsa == null)
          {
              if(pubxml == null)
                throw new ApplicationException("No Public key defined");
              rsa = new RSACryptoServiceProvider();
              rsa.FromXmlString(pubxml);
          }
       }

       private string  pubxml        = null;

       [ NonSerialized ]
       protected RSA rsa = null;

    } // END: class SecureBag

    [Serializable]
    public sealed class CCard : SecureBag, ICCard  
    {
       
       public string CardNumber 
       { 
          get
          {
             return DecryptString(encCardNumber);
          }
          set
          {
             encCardNumber = EncryptString(value);  
          }
       }
       public string HolderName 
       { 
          get
          {
             return DecryptString(encHolderName);
          }
          set
          {
             encHolderName = EncryptString(value);  
          }
       }
       public string ZipCode   
       { 
          get
          {
             return DecryptString(encZipCode);
          }
          set
          {
             encZipCode = EncryptString(value);  
          }
       }
       public DateTime  ExpiryDate 
       { 
          get
          {
             return expDt;
          }
          set
          {
             expDt = value;
          }
       }
       public CardTypes CType 
       { 
          get
          {
             return ctyp;
          }
          set
          {
             ctyp = value;
          }
       }

      
       private DateTime  expDt;       
       private CardTypes ctyp        = CardTypes.Undefined;
       private byte [] encCardNumber = null;
       private byte [] encHolderName = null;
       private byte [] encZipCode    = null;
       

   
    } // END: class CCard
    
    [Serializable]
    public sealed class Charge : SecureBag, ICharge
    {
       public string MerchantId
       {
          get
          {
             return DecryptString(encMerchantId);
          }
          set
          {
             encMerchantId = EncryptString(value);  
          }
       }
       
       public double Amount     
       {
          get
          {
               return Convert.ToDouble(DecryptString(encAmount));
          }
          set
          {
             string str = Convert.ToString(value); 
             Console.WriteLine("Charge Amt = {0}",str);
             encAmount = EncryptString(str);
          }
       }
       
       public string CurrencyName 
       { 
         get { return curn;}  
         set { curn = value;}
       }

       public string InvoiceRef 
       {
          get { return invref; }
          set { invref = value;}
           
       }

       private byte[] encMerchantId = null;
       private byte[] encAmount = null;
       private string invref = null;
       private string curn = null;
    
    } // END: class Charge


} // END: namesapce CARD