// <copyright file="FinancialCardIssuer.cs" company="Scriptel Corporation">
//      Copyright 2014 - Scriptel Corporation
// </copyright>
namespace EasyScriptAPI
{
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    /// <summary>
    /// Enumeration containing known financial card issuers.
    /// </summary>
    public enum FinancialCardIssuerName
    {
        /// <summary>
        /// Enumeration entry for American Express.
        /// </summary>
        AMERICAN_EXPRESS,

        /// <summary>
        /// Enumeration entry for Diner's club.
        /// </summary>
        DINERS_CLUB,

        /// <summary>
        /// Enumeration entry for Carte Blanch.
        /// </summary>
        CARTE_BLANCH,

        /// <summary>
        /// Enumeration entry for Discover Card.
        /// </summary>
        DISCOVER,

        /// <summary>
        /// Enumeration entry for Enroute.
        /// </summary>
        ENROUTE,

        /// <summary>
        /// Enumeration entry for JCB.
        /// </summary>
        JCB,

        /// <summary>
        /// Enumeration entry for Master Card.
        /// </summary>
        MASTER_CARD,

        /// <summary>
        /// Enumeration entry for VISA.
        /// </summary>
        VISA,

        /// <summary>
        /// Enumeration entry for unknown cards.
        /// </summary>
        UNKNOWN
    }

    /// <summary>
    /// This class attempts to identify credit card issuers based on patterns in the
    /// numbers each vendor issues.
    /// </summary>
    public class FinancialCardIssuer
    {
        /// <summary>
        /// Maps the FinancialCardIssuer enumeration to an actual FinancialCardIssuer object.
        /// </summary>
        private static Dictionary<FinancialCardIssuerName, FinancialCardIssuer> issuers = null;
    
        /// <summary>
        /// name of the issuer
        /// </summary>
        private string issuerName;

        /// <summary>
        /// Regex to match credit cards to this issuer.
        /// </summary>
        private string regex;

        /// <summary>
        /// Initializes a new instance of the <see cref="FinancialCardIssuer" /> class.
        /// </summary>
        /// <param name="issuerName">Human-friendly name of the issuer.</param>
        /// <param name="regex">Regular expression needed to identify the card.</param>
        private FinancialCardIssuer(string issuerName, string regex)
        {
            this.issuerName = issuerName;
            this.regex = regex;
        }
         
        /// <summary>
        ///  This method attempts to identify the issuer of a credit card based on
        ///  a credit card number.
        /// </summary>
        /// <param name="number">Number to inspect</param>
        /// <returns>Issuer if identified, UNKNOWN otherwise.</returns>
        public static FinancialCardIssuer IdentifyByCardNumber(string number)
        {
            InitializeIssuers();
            foreach (FinancialCardIssuerName issuerName in issuers.Keys)
            {
                FinancialCardIssuer issuer = issuers[issuerName];
                if (issuer.GetRegex().IsMatch(number))
                {
                    return issuer;
                }
            }

            return issuers[FinancialCardIssuerName.UNKNOWN];
        } 

        /// <summary>
        /// Gets the issuer name.
        /// </summary>
        /// <returns>Human-friendly issuer name</returns>
        public string GetIssuerName()
        {
            return this.issuerName;
        }

        /// <summary>
        /// Gets the regular expression string.
        /// </summary>
        /// <returns>regular expression string</returns>
        public string GetRegexString()
        {
            return this.regex;
        }
    
        /// <summary>
        ///  This method gets the regular expression pattern used to match the card
        ///  number for this member.
        /// </summary>
        /// <returns>Regular expression pattern</returns>
        public Regex GetRegex()
        {
            return new Regex(this.regex);
        }

        /// <summary>
        /// Initializes the dictionary of credit card issuers
        /// </summary>
        private static void InitializeIssuers()
        {
            if (issuers == null)
            {
                issuers = new Dictionary<FinancialCardIssuerName, FinancialCardIssuer>();

                issuers.Add(FinancialCardIssuerName.AMERICAN_EXPRESS, new FinancialCardIssuer("American Express", "^(34|37)\\d{13}$"));
                issuers.Add(FinancialCardIssuerName.DINERS_CLUB, new FinancialCardIssuer("Diners Club", "^(30[0-5]\\d{11}|36\\d{12})$"));
                issuers.Add(FinancialCardIssuerName.CARTE_BLANCH, new FinancialCardIssuer("Carte Blanche", "^38\\d{12}$"));
                issuers.Add(FinancialCardIssuerName.DISCOVER, new FinancialCardIssuer("Discover", "^6011\\d{12}$"));
                issuers.Add(FinancialCardIssuerName.ENROUTE, new FinancialCardIssuer("EnRoute", "^(2131|1800)\\d{11}$"));
                issuers.Add(FinancialCardIssuerName.JCB, new FinancialCardIssuer("JCB", "^(3\\d{15}|(2131|1800)\\d{11})$"));
                issuers.Add(FinancialCardIssuerName.MASTER_CARD, new FinancialCardIssuer("Master Card", "^5[1-5]\\d{14}$"));
                issuers.Add(FinancialCardIssuerName.VISA, new FinancialCardIssuer("Visa", "^4\\d{12,15}$"));
                issuers.Add(FinancialCardIssuerName.UNKNOWN, new FinancialCardIssuer("Unknown", ".*"));
            }
        }
    }
}
