content: /*
   * CDDL HEADER START
   *
   * The contents of this file are subject to the terms of the Common Development
   * and Distribution License (the "License").
   * You may not use this file except in compliance with the License.
   *
   * You can obtain a copy of the license at
   * src/com/vodafone360/people/VODAFONE.LICENSE.txt or
   * http://github.com/360/360-Engine-for-Android
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   * When distributing Covered Code, include this CDDL HEADER in each file and
   * include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
   * If applicable, add the following below this CDDL HEADER, with the fields
   * enclosed by brackets "[]" replaced with your own identifying information:
   * Portions Copyright [yyyy] [name of copyright owner]
   *
   * CDDL HEADER END
   *
   * Copyright 2010 Vodafone Sales & Services Ltd.  All rights reserved.
   * Use is subject to license terms.
   */
  
  package com.vodafone360.people.utils;
  
  import java.util.HashMap;
  import java.util.Map;
  
  import android.content.Context;
  import android.telephony.TelephonyManager;
  
  /**
   * The SimCard class provides utility methods to access SIM card data.
   */
  public class SimCard {
  
      /**
       * Digits beyond this count will be replaced by 0.
       */
      private static final int ANONYMISED_DIGITS = 4;
      
      /**
       * The Network.
       */
      public enum Network {
  
          CH("ch", 41), // Switzerland
          DE("de", 49), // Germany
          FR("fr", 33), // France
          GB("gb", 44), // Great Britain
          IE("ie", 353), // Ireland
          IT("it", 39), // Italy
          NL("nl", 31), // Netherlands
          SE("se", 46), // Sweden
          TR("tr", 90), // Turkey
          TW("tw", 886), // Taiwan
          US("us", 1), // United States
          ES("es", 34), // Spain
          // ZA("za", 260), //Zambia/VodaCom-SA??
          UNKNOWN("unknown", 0);
  
          private final String mIso;
  
          private final int mPrefix;
  
          private Network(String iso, int prefix) {
              mIso = iso;
              mPrefix = prefix;
          }
  
          private Network() {
              mIso = null;
              mPrefix = -1;
          }
  
          public String iso() {
              return mIso;
          }
  
          protected int prefix() {
              return mPrefix;
          }
  
          /***
           * Returns the SimNetwork of a given ISO if known
           *
           * @param iso Country ISO value.
           * @return SimNetwork or SimNetwork.UNKNOWN if not found.
           */
          public static Network getNetwork(String iso) {
              for (final Network network : Network.values()) {
                  if (network.iso().equals(iso)) {
                      return network;
                  }
              }
              return UNKNOWN;
          }
      }
      
      /**
       * SIM card absent state.
       * @see #getSubscriberId(Context)
       */
      public final static String SIM_CARD_ABSENT = "SimAbsent";
      
      /**
       * SIM card not readable state.
       * @see #getSubscriberId(Context)
       */
      public final static String SIM_CARD_NOT_READABLE = "SimNotReadable";
      
      /**
       * Gets the SIM card state.
       * 
       * @see TelephonyManager#getSimState()
       * 
       * @param context the application context
       * @return the SIM card state
       */
      public static int getState(Context context) {
         
          try {
              
              final TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
              
              return telephonyManager.getSimState();  
              
          } catch (final Exception e) {
              LogUtils.logE("SimCard.getState() - Exception:", e);
          }
          
          return TelephonyManager.SIM_STATE_UNKNOWN;
      }
      
      /**
       * Tells whether or not the SIM card is present.
       * 
       * @param context the 
       * @return true if the SIM is ready, false otherwise (not ready or absent)
       */
      public static boolean isSimReady(Context context) {
          
          return getState(context) == TelephonyManager.SIM_STATE_READY;
      }
      
      /**
       * Gets the Subscriber Id.
       * 
       * @see SIM_CARD_NOT_READABLE
       * @see SIM_CARD_ABSENT
       * 
       * @param databaseHelper the DatabaseHelper
       * @return the Subscriber Id or SIM_CARD_ABSENT or SIM_CARD_NOT_READABLE
       */
      public static String getSubscriberId(Context context) {
          
          if (getState(context) == TelephonyManager.SIM_STATE_ABSENT) {
              
              return SIM_CARD_ABSENT;
              
          } else {
              
              try {
                  
                  final TelephonyManager mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
                  
                  return mTelephonyManager.getSubscriberId(); 
      
              } catch (final Exception e) {
                  
                  LogUtils.logE("SimCard.getSubscriberId() - Exception: "+e);
              }
          }
          return SIM_CARD_NOT_READABLE;
      }
      
      /**
       * Logs a MSISDN validation failure event to Flurry.
       *
       * @param context Android context.
       * @param workflow Given work flow (either sign in or sign up).
       * @param status Current status string.
       * @param enteredMsisdn User provided MSISDN.
       */
      public static void logMsisdnValidationFail(Context context, String workflow, String status,
              String enteredMsisdn) {
          final TelephonyManager telephonyManager = (TelephonyManager)context
                  .getSystemService(Context.TELEPHONY_SERVICE);
          final Map<String, String> map = new HashMap<String, String>();
          map.put("NetworkCountryIso", telephonyManager.getNetworkCountryIso());
          map.put("NetworkOperator", telephonyManager.getNetworkOperator());
          map.put("NetworkOperatorName", telephonyManager.getNetworkOperatorName());
          map.put("SimCountryIso", telephonyManager.getSimCountryIso());
          map.put("SimOperator", telephonyManager.getSimOperator());
          map.put("SimOperatorName", telephonyManager.getSimOperatorName());
          map.put("AnonymisedMsisdn", getAnonymisedMsisdn(telephonyManager.getLine1Number()));
          map.put("AnonymisedEntereddMsisdn", getAnonymisedMsisdn(enteredMsisdn));
          map.put("Workflow", workflow);
          map.put("Error", status);
          // FlurryAgent.onEvent("EnterMobileNumberActivity_FAIL", map);
  
          LogUtils.logV("SimUtils.logMsisdnValidationFail() enteredMsisdn[" + enteredMsisdn + "]");
      }
  
      /**
       * Retrieves the full international MSISDN number from the SIM or NULL if
       * unavailable or unsure. Note: This functionality is currently part of
       * SignupEnterMobileNumberActivity so anonymised data can be sent back to
       * Flurry, in order to verify this program logic on multiple SIMs.
       *
       * @param context Android Context
       * @return Full international MSISDN, or NULL if unsure of conversion.
       */
      public static String getFullMsisdn(Context context) {
          final TelephonyManager telephonyManager = (TelephonyManager)context
                  .getSystemService(Context.TELEPHONY_SERVICE);
          final String rawMsisdn = telephonyManager.getLine1Number();
          final String verifyedMsisdn = getVerifyedMsisdn(rawMsisdn, telephonyManager
                  .getNetworkCountryIso(), telephonyManager.getNetworkOperatorName(),
                  telephonyManager.getNetworkOperator());
          final Map<String, String> map = new HashMap<String, String>();
          map.put("NetworkCountryIso", telephonyManager.getNetworkCountryIso());
          map.put("NetworkOperator", telephonyManager.getNetworkOperator());
          map.put("NetworkOperatorName", telephonyManager.getNetworkOperatorName());
          map.put("SimCountryIso", telephonyManager.getSimCountryIso());
          map.put("SimOperator", telephonyManager.getSimOperator());
          map.put("SimOperatorName", telephonyManager.getSimOperatorName());
          map.put("AnonymisedMsisdn", getAnonymisedMsisdn(rawMsisdn));
          map.put("AnonymisedVerifyedMsisdn", getAnonymisedMsisdn(verifyedMsisdn));
          // FlurryAgent.onEvent("EnterMobileNumberActivity", map);
          return verifyedMsisdn;
      }
  
      /***
       * Convert raw MSISDN to a verified MSISDN with country code.
       *
       * @param rawMsisdn Unverified MSISDN.
       * @param countryIso Country ISO value from the SIM.
       * @param networkOperatorName Network operator name value from the SIM.
       * @param networkOperator Network operator value from the SIM.
       * @return Verified MSISDN, or "" if NULL or unsure of country code.
       */
      public static String getVerifyedMsisdn(String rawMsisdn, String countryIso,
              String networkOperatorName, String networkOperator) {
          if (rawMsisdn == null || rawMsisdn.trim().equals("")) {
              // Reject any NULL or empty values.
              return "";
  
          } else if (rawMsisdn.substring(0, 1).equals("+")) {
              // Accept any values starting with "+".
              return rawMsisdn;
  //            the MTS Russian SIM may have just "8" as a rawNsisdn string
          } else if (rawMsisdn.length() > 1 && (rawMsisdn.substring(0, 2).equals("00"))) {
              // Accept any values starting with "00", but at +.
              return "+" + rawMsisdn.substring(2);
  
          } else if (countryIso != null && !countryIso.trim().equals("")) {
              // Filter known values:
              try {
                  final Network simNetwork = Network.getNetwork(countryIso);
                  if (simNetwork != Network.UNKNOWN) {
                      return "+" + smartAdd(simNetwork.prefix() + "", dropZero(rawMsisdn));
                  } else {
                      // Rejected
                      return "";
                  }
  
              } catch (final NumberFormatException e) {
                  // Rejected
                  return "";
              }
  
          } else {
              // Rejected
              return "";
          }
      }
  
      /***
       * Concatenate the "start" value with the "end" value, except where the
       * "start" value is already in place.
       *
       * @param start First part of String.
       * @param end Last part of String.
       * @return "start" + "end".
       */
      private static String smartAdd(String start, String end) {
          if (end == null || end.trim().equals("")) {
              return "";
          } else if (end.startsWith(start)) {
              return end;
          } else {
              return start + end;
          }
      }
  
      /***
       * Remove the preceding zero, if present.
       *
       * @param rawMsisdn Number to alter.
       * @return Number without the zero.
       */
      private static String dropZero(String rawMsisdn) {
          if (rawMsisdn == null || rawMsisdn.trim().equals("")) {
              return "";
          } else if (rawMsisdn.startsWith("0")) {
              return rawMsisdn.substring(1);
          } else {
              return rawMsisdn;
          }
      }
  
      /***
       * Converts an identifiable MSISDN value to something that can be sent via a
       * third party. E.g. "+49123456789" becomes "+49100000000".
       *
       * @param input Private MSISDN.
       * @return Anonymous MSISDN.
       */
      public static String getAnonymisedMsisdn(String input) {
          if (input == null || input.trim().equals("")) {
              return "";
          } else {
              final int length = input.length();
              final StringBuffer result = new StringBuffer();
              for (int i = 0; i < length; i++) {
                  if (i < ANONYMISED_DIGITS) {
                      result.append(input.charAt(i));
                  } else {
                      result.append("0");
                  }
              }
              return result.toString();
          }
      }
  }
  