using Microsoft.VisualBasic.FileIO;
using System.Collections.Generic;
using System.IO;
using System;
namespace Contacts
{
///
/// Represents a file, and provides implementations for parsing contacts from a file.
///
public class Resolver
{
public List Contacts { get; set; }
internal string _filepath;
private bool isGoogleCsv;
public Resolver(string filepath)
{
_filepath = filepath;
if (!File.Exists(_filepath))
throw new InvalidOperationException("File does not exist.");
Contacts = new List();
}
///
/// Manages the parsing process and determines the correct parser to use based upon the filetype.
///
public void Parse()
{
string filetype = _filepath.Substring(_filepath.LastIndexOf('.'));
switch (filetype)
{
case ".csv":
ParseCsv();
break;
case ".vcf":
ParseVCF();
break;
case ".card":
ParseVCF();
break;
}
}
///
/// Convert a CSV file into a List, and determine if the input csv is in the Google contact format or the Outlook contact format.
///
private void ParseCsv()
{
List contactInfo = new List();
using (TextFieldParser parser = new TextFieldParser(_filepath))
{
if (parser.PeekChars(5).Equals("Name,"))
isGoogleCsv = true;
else
isGoogleCsv = false;
parser.ReadLine(); // skip header row
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Processing row
string[] fields = parser.ReadFields();
foreach (string field in fields)
if (!field.Equals("")) // skip blank fields
contactInfo.Add(field);
parser.ReadLine(); // move to next line to read the next contact.
ConvertToContact(contactInfo); // with current contact information, generate and add the new contact.
contactInfo.Clear(); // clear contact information for next contact.
}
}
}
///
/// Parse the information contained by a Google formatted .csv file to generate a new Contacts object.
///
private void ConvertToContact(List csv)
{
Phone home = null;
Phone work = null;
Phone cell = null;
Phone other = null;
Contact c;
string[] contact = csv.ToArray();
// Check if the csv is a google or outlook formatted csv.
if (isGoogleCsv)
c = new Contact(contact[1], contact[2].Contains("*") ? "" : contact[2], null);
else
c = new Contact(contact[0], contact[1].Contains("*") ? "" : contact[1], null);
// iterate through csv array
for (int i = 0; i < contact.Length; i++)
{
// if current element is labeled as a number,
switch (contact[i])
{
case "Home":
home = ParsePhone(PhoneType.Home, contact[i + 1]);
if (home != null)
c.AddPhone(home);
break;
case "Work":
work = ParsePhone(PhoneType.Work, contact[i + 1]);
if (work != null)
c.AddPhone(work);
break;
case "Job":
work = ParsePhone(PhoneType.Work, contact[i + 1]);
if (work != null)
c.AddPhone(work);
break;
case "Mobile":
cell = ParsePhone(PhoneType.Cell, contact[i + 1]);
if (cell != null)
c.AddPhone(cell);
break;
case "Cell":
cell = ParsePhone(PhoneType.Cell, contact[i + 1]);
if (cell != null)
c.AddPhone(cell);
break;
case "Other":
other = ParsePhone(PhoneType.Other, contact[i + 1]);
if (other != null)
c.AddPhone(other);
break;
default:
other = ParsePhone(PhoneType.Other, contact[i]);
if (other != null)
c.AddPhone(other);
break;
}
if (contact[i].Contains("@")) // detect an email address and add to the current contact.
c.AddEmail(contact[i]);
if (contact[i].Contains("http") ||
contact[i].Contains("www.")) // detect a URL and add to the current contact.
c.PictureUrl = contact[i];
}
Contacts.Add(c);
}
///
/// Parse the information contained by the .vcf file to generate a new Contacts object.
///
private void ParseVCF()
{
using (StreamReader reader = new StreamReader(_filepath))
{
string line;
Contact contact = null;
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith("BEGIN:VCARD"))
{
contact = new Contact();
}
else if (line.StartsWith("FN:") && contact != null)
{
//mabye wrong
string myLine = line;
int i = 0;
while (true)
{
if (myLine[i].Equals(" "))
{
break;
}
else
{
contact.FirstName += myLine[i];
i++;
}
}
//now at last name
while (true)
{
//mabye change
if (i == myLine.Length)
{
break;
}
else
{
contact.LastName += myLine[i];
}
}
}
else if (line.StartsWith("TEL;TYPE=") && contact != null)
{
int typeEndIndex = line.IndexOf(':', 9);
string phoneType = line.Substring(9, typeEndIndex - 9).ToUpper();
string phoneNumber = line.Substring(typeEndIndex + 1);
PhoneType parsedPhoneType = PhoneType.Other;
switch (phoneType)
{
case "HOME":
parsedPhoneType = PhoneType.Home;
break;
case "WORK":
parsedPhoneType = PhoneType.Work;
break;
case "CELL":
parsedPhoneType = PhoneType.Cell;
break;
case "OTHER":
parsedPhoneType = PhoneType.Other;
break;
}
Phone phone = ParsePhone(parsedPhoneType, phoneNumber);
if (phone != null)
{
contact.AddPhone(phone);
}
}
else if (line.StartsWith("EMAIL:") && contact != null)
{
string email = line.Substring(6);
contact.AddEmail(email);
}
else if (line.StartsWith("PHOTO;VALUE=URI:") && contact != null)
{
string pictureUrl = line.Substring(15);
contact.PictureUrl = pictureUrl;
}
else if (line.StartsWith("END:VCARD") && contact != null)
{
Contacts.Add(contact);
contact = null;
}
}
}
}
///
/// Parses any format of a phone number into the acceptable format 1234567890.
///
///
///
///
private Phone ParsePhone(PhoneType type, string number)
{
List list = new List();
char[] characters = number.ToCharArray();
for (int i = 0; i < characters.Length; i++)
if (char.IsDigit(characters[i])) // if the character is a digit, add it to the list
list.Add(characters[i]);
if (list.Count == 11) // remove the international code
list.RemoveAt(0);
string outputNumber = string.Join("", list);
if (outputNumber.Length > 10 ||
outputNumber.Length <
10) // detect if this was an email or address labeled as a generic category, ie. "Home".
return null;
return new Phone(outputNumber, type);
}
}
}