package org.mots.haxsync.services;

import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.mots.haxsync.R;
import org.mots.haxsync.provider.FacebookFQLFriend;
import org.mots.haxsync.provider.FacebookGraphFriend;
import org.mots.haxsync.provider.Status;
import org.mots.haxsync.utilities.BitmapUtil;
import org.mots.haxsync.utilities.ContactUtil;
import org.mots.haxsync.utilities.ContactUtil.Photo;
import org.mots.haxsync.utilities.DeviceUtil;
import org.mots.haxsync.utilities.FacebookUtil;
import org.mots.haxsync.utilities.RootUtil;
import org.mots.haxsync.utilities.WebUtil;

import com.jjnford.android.util.Shell.ShellException;

import android.accounts.Account;
import android.accounts.OperationCanceledException;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.SyncResult;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.RawContacts.Entity;
import android.util.Log;

public class ContactsSyncAdapterService extends Service {
	private static final String TAG = "ContactsSyncAdapterService";
	private static SyncAdapterImpl sSyncAdapter = null;
	public static ContentResolver mContentResolver = null;
	private static String UsernameColumn = ContactsContract.RawContacts.SYNC1;
	private static String PhotoTimestampColumn = ContactsContract.RawContacts.SYNC2;

	public ContactsSyncAdapterService() {
		super();
	}

	private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
		private Context mContext;

		public SyncAdapterImpl(Context context) {
			super(context, true);
			mContext = context;
		}

		@Override
		public void onPerformSync(Account account, Bundle extras,
				String authority, ContentProviderClient provider,
				SyncResult syncResult) {
			try {
				ContactsSyncAdapterService.performSync(mContext, account,
						extras, authority, provider, syncResult);
			} catch (OperationCanceledException e) {
			}
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		IBinder ret = null;
		ret = getSyncAdapter().getSyncAdapterBinder();
		return ret;
	}

	private SyncAdapterImpl getSyncAdapter() {
		if (sSyncAdapter == null)
			sSyncAdapter = new SyncAdapterImpl(this);
		return sSyncAdapter;
	}
	
	private static String matches(Set<String> phoneContacts, String fbContact, int maxdistance){
		if (maxdistance == 0){
			if (phoneContacts.contains(fbContact)){
				return fbContact;
			}
			return null;
			//return phoneContacts.contains(fbContact);
		}
		int bestDistance = maxdistance;
		String bestMatch = null;
		for (String contact : phoneContacts){
			int distance = StringUtils.getLevenshteinDistance(contact != null ? contact.toLowerCase() : "", fbContact != null ? fbContact.toLowerCase() : "");
			if( distance <= bestDistance){
				//Log.i("FOUND MATCH", "Phone Contact: " + contact +" FB Contact: " + fbContact +" distance: " + distance + "max distance: " +maxdistance);
				bestMatch = contact;
				bestDistance = distance;
			}
		}
		return bestMatch;
	}

	private static void addContact(Account account, String name, String username) {
		ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();

		ContentProviderOperation.Builder builder = ContentProviderOperation
				.newInsert(RawContacts.CONTENT_URI);
		builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
		builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
		builder.withValue(RawContacts.SYNC1, username);
		operationList.add(builder.build());

		builder = ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI);
		builder.withValueBackReference(
				ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID,
				0);
		builder.withValue(
				ContactsContract.Data.MIMETYPE,
				ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
		builder.withValue(
				ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
				name);
		operationList.add(builder.build());

		builder = ContentProviderOperation
				.newInsert(ContactsContract.Data.CONTENT_URI);
		builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
		builder.withValue(ContactsContract.Data.MIMETYPE,
				"vnd.android.cursor.item/vnd.org.mots.haxsync.profile");
		builder.withValue(ContactsContract.Data.DATA1, username);
		builder.withValue(ContactsContract.Data.DATA2, "Facebook Profile");
		builder.withValue(ContactsContract.Data.DATA3, "View profile");
		operationList.add(builder.build());

		try {
			mContentResolver.applyBatch(ContactsContract.AUTHORITY,
					operationList);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private static void addSelfContact(Account account, int maxSize, boolean square, boolean faceDetect, boolean force, boolean root, int rootsize, File cacheDir, boolean google) {
		
		Uri rawContactUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI.buildUpon()
				.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
				.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
				.build();
		
		long ID = -2;
		String username = null;
		String email = null;
        FacebookGraphFriend user = FacebookUtil.getSelfInfo();
        if (user == null)
            return;
        Cursor cursor = mContentResolver.query(rawContactUri, new String[] {BaseColumns._ID, UsernameColumn}, null, null, null);
        if (cursor.getCount() > 0){
        	cursor.moveToFirst();
        	ID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
        	username = cursor.getString(cursor.getColumnIndex(UsernameColumn));
        	cursor.close();
        } else {
        	cursor.close();
            username = user.getUserName();
            email = user.getEmail();

        	
        	ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();

        	ContentProviderOperation.Builder builder = ContentProviderOperation
        			.newInsert(ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI);
        	builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
        	builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
        	builder.withValue(RawContacts.SYNC1, username);
        	operationList.add(builder.build());

        	builder = ContentProviderOperation
        			.newInsert(ContactsContract.Data.CONTENT_URI);
        	builder.withValueBackReference(
        			ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID,
        			0);
        	builder.withValue(
        			ContactsContract.Data.MIMETYPE,
        			ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
        	builder.withValue(
        			ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
        			account.name);
        	operationList.add(builder.build());

        	builder = ContentProviderOperation
        			.newInsert(ContactsContract.Data.CONTENT_URI);
        	builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
        	builder.withValue(ContactsContract.Data.MIMETYPE,
        			"vnd.android.cursor.item/vnd.org.mots.haxsync.profile");
        	builder.withValue(ContactsContract.Data.DATA1, username);
        	builder.withValue(ContactsContract.Data.DATA2, "Facebook Profile");
        	builder.withValue(ContactsContract.Data.DATA3, "View profile");
        	operationList.add(builder.build());
        	
        	if (email != null){
	        	builder = ContentProviderOperation
	        			.newInsert(ContactsContract.Data.CONTENT_URI);
	        	builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0);
	        	builder.withValue(ContactsContract.Data.MIMETYPE,
	        			ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
	        	builder.withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
	        	operationList.add(builder.build());
        	}

        	try {
        		mContentResolver.applyBatch(ContactsContract.AUTHORITY,
        				operationList);
        	} catch (Exception e) {
        		// TODO Auto-generated catch block
        		e.printStackTrace();
        		return;
        	}
            cursor = mContentResolver.query(rawContactUri, new String[] {BaseColumns._ID}, null, null, null);
            if (cursor.getCount() > 0){
            	cursor.moveToFirst();
            	ID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
            	cursor.close();
            } else{
            	Log.i(TAG, "NO SELF CONTACT FOUND");
            	return;
            }
        }
        Log.i("self contact", "id: "+ID+" uid: "+ username);
        if (ID != -2 && username != null){

        updateContactPhoto(ID, 0, maxSize, square, user.getPicURL(), faceDetect, true, root, rootsize, cacheDir, google, true);


        }
	}

	
	
	

	

	private static void updateContactStatus(long rawContactId, String status,
			long timeStamp) {
		if (status != null && timeStamp != 0){
		ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
		Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
				rawContactId);
		Uri entityUri = Uri.withAppendedPath(rawContactUri,
				Entity.CONTENT_DIRECTORY);
		Cursor c = mContentResolver.query(entityUri, new String[] {
				RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE,
				Entity.DATA1 }, null, null, null);
		try {
			while (c.moveToNext()) {
				if (!c.isNull(1)) {
					String mimeType = c.getString(2);

					if (mimeType
							.equals("vnd.android.cursor.item/vnd.org.mots.haxsync.profile")) {
						ContentProviderOperation.Builder builder = ContentProviderOperation
								.newInsert(ContactsContract.StatusUpdates.CONTENT_URI);
						builder.withValue(
								ContactsContract.StatusUpdates.DATA_ID,
								c.getLong(1));
						builder.withValue(
								ContactsContract.StatusUpdates.STATUS, status);
						builder.withValue(
								ContactsContract.StatusUpdates.STATUS_RES_PACKAGE,
								"org.mots.haxsync");
						builder.withValue(
								ContactsContract.StatusUpdates.STATUS_LABEL,
								R.string.app_name);
						builder.withValue(
								ContactsContract.StatusUpdates.STATUS_ICON,
								R.drawable.icon);
						builder.withValue(
								ContactsContract.StatusUpdates.STATUS_TIMESTAMP,
								timeStamp);
						operationList.add(builder.build());
					}
				}
			}
		} finally {
			c.close();
		}
		try {
			mContentResolver.applyBatch(ContactsContract.AUTHORITY,
					operationList);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OperationApplicationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		}
	}
	
	private static void updateContactPhoto(long rawContactId, long timestamp, int maxSize, boolean square, String imgUrl, boolean faceDetect, boolean force, boolean root, int rootsize, File cacheDir, boolean google, boolean primary) {
		if (imgUrl != null){

		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";

		//getting the old timestamp
		String oldurl = "";
		boolean newpic = force;
		
		if (!newpic){
			Cursor c1 = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.Data.SYNC3 }, where , null, null);
			if (c1.getCount() > 0){
				c1.moveToLast();

				if (!c1.isNull(c1.getColumnIndex(ContactsContract.Data.SYNC3))){
					oldurl = c1.getString(c1.getColumnIndex(ContactsContract.Data.SYNC3));
					//Log.i(TAG, "read old timestamp: " + oldTimestamp);
				}
			}
			c1.close();
			
			//Log.i(TAG, "Old Timestamp " +String.valueOf(oldTimestamp) + "new timestamp: " + String.valueOf(timestamp));

				if (!oldurl.equals(imgUrl)){
					Log.i(TAG, "OLD URL: " + oldurl);
					Log.i(TAG, "NEW URL: " + imgUrl);
					newpic = true;
				}
				

		}

		if (newpic){
			Log.i(TAG, "getting new image, "+imgUrl);
		//	Log.i(TAG, "Old Timestamp " +String.valueOf(oldTimestamp) + "new timestamp: " + String.valueOf(timestamp));

			byte[] photo = WebUtil.download(imgUrl);
			byte[] origPhoto = photo;
			
			/*if(square)
				photo = BitmapUtil.resize(photo, maxSize, faceDetect);*/
			
			ContactUtil.Photo photoi = new Photo();
			photoi.data = photo;
			photoi.timestamp = timestamp;
			photoi.url = imgUrl;
			
			ContactUtil.updateContactPhoto(mContentResolver, rawContactId, photoi, primary);



		if (root){
			Cursor c1 = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] { ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID}, where , null, null);
			if (c1.getCount() > 0){
				c1.moveToLast();
				String photoID = c1.getString(c1.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID));
				c1.close();
				if (photoID != null){
					photo = BitmapUtil.resize(origPhoto, rootsize, faceDetect);
					String picpath = DeviceUtil.saveBytes(photo, cacheDir);
					try {
						String newpath = RootUtil.movePic(picpath, photoID);
						RootUtil.changeOwner(newpath);
					} catch (Exception e) {
						Log.e("ROOT EXCEPTION", e.getMessage());
						// TODO: handle exception
					}
				}
			}
			
		}
		Log.i("google photo sync", String.valueOf(google));
		if (google){
			for (long raw : ContactUtil.getRawContacts(mContentResolver, rawContactId, "com.google")){
				Log.i("google rawid", String.valueOf(raw));
				ContactUtil.updateContactPhoto(mContentResolver, raw, photoi, false);
			}
		}
		}
		}
	}

	public static class SyncEntry {
		public Long raw_id = 0L;
	}
	
	private static HashMap<String, Long> loadHTCData(Context c){
		mContentResolver = c.getContentResolver();
		/*ArrayList<Long> contactIDs = new ArrayList<Long>();
		Cursor c1 = mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, new String[] { BaseColumns._ID }, ContactsContract.Contacts.IN_VISIBLE_GROUP +" = 1", null, null);
		while (c1.moveToNext()){
			contactIDs.add(c1.getLong(c1.getColumnIndex(BaseColumns._ID)));
		}
		c1.close();*/
		
		
		HashMap<String, Long> contacts = new HashMap<String, Long>();
		//Cursor cursor = mContentResolver.query(ContactsContract.Data.CONTENT_URI, null, ContactsContract.Data.MIMETYPE +"= ?", ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE, null);
        String noteWhere = ContactsContract.Data.MIMETYPE + " = ?";
        String[] noteWhereParams = new String[]{ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE};
        Cursor cursor = mContentResolver.query(ContactsContract.Data.CONTENT_URI, new String[] {ContactsContract.Data.RAW_CONTACT_ID, ContactsContract.CommonDataKinds.Note.NOTE}, noteWhere, noteWhereParams, null);
        while (cursor.moveToNext()) {
        	try{
            String note = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE));
            if (note != null){
	            if (note.startsWith("<HTCData>")){
					Pattern fbPattern = Pattern.compile("<Facebook>id:(.*)/friendof.*</Facebook>", Pattern.CASE_INSENSITIVE);
					Matcher fbMatcher = fbPattern.matcher(note);
					
					while (fbMatcher.find()){
						String uid = fbMatcher.group(1);
						//Log.i("found HTCDATA", uid);
		            	Long rawID = cursor.getLong(cursor.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID));
		            	contacts.put(uid, rawID);
					}
	
	            	//String uid = note.split("/friendof")[0].substring(22);
	
	            }
            }
        	} catch (IllegalStateException e){
        		Log.e(TAG, "Error loading HTCDATA");
        		break;
        	}
        }
        cursor.close();
		return contacts;	
	}
	
	private static HashMap<String, Long> loadPhoneContacts(Context c){
		mContentResolver = c.getContentResolver();
		HashMap<String, Long> contacts = new HashMap<String, Long>();
		Cursor cursor = mContentResolver.query(
				Phone.CONTENT_URI,
				   new String[]{Phone.DISPLAY_NAME, Phone.RAW_CONTACT_ID},
				   null,
				   null,
				   null);
		while (cursor.moveToNext()) {
			contacts.put(cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)), cursor.getLong(cursor.getColumnIndex(Phone.RAW_CONTACT_ID)));
			//names.add(cursor.getString(cursor.getColumnIndex(Phone.DISPLAY_NAME)));
		}
		cursor.close();
		return contacts;	
	}
	
	
	public static HashMap<String, SyncEntry> getLocalContacts(Account account){
		Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
				.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
				.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
				.build();
		HashMap<String, SyncEntry> localContacts = new HashMap<String, SyncEntry>();
		Cursor c1 = mContentResolver.query(rawContactUri, new String[] { BaseColumns._ID, UsernameColumn, PhotoTimestampColumn }, null, null, null);
		while (c1.moveToNext()) {
			SyncEntry entry = new SyncEntry();
			entry.raw_id = c1.getLong(c1.getColumnIndex(BaseColumns._ID));
			localContacts.put(c1.getString(1), entry);
		}
		c1.close();
		return localContacts;
	}

	@SuppressWarnings("unused")
	private static void performSync(Context context, Account account,
			Bundle extras, String authority, ContentProviderClient provider,
			SyncResult syncResult) throws OperationCanceledException {
		SharedPreferences prefs = context.getSharedPreferences(context.getPackageName() + "_preferences", MODE_MULTI_PROCESS);
		
		mContentResolver = context.getContentResolver();

		FacebookUtil.refreshPermissions(context);


        //TODO: Clean up stuff that isn't needed anymore since Graph API
		boolean cropPhotos = true;
    	boolean sync = prefs.getBoolean("sync_status", true);
    	boolean syncNew = prefs.getBoolean("status_new", true);
    	boolean syncLocation = prefs.getBoolean("sync_location", true);
    	boolean syncSelf = prefs.getBoolean("sync_self", false);
        boolean imageDefault = prefs.getBoolean("image_primary", true);
    	    	
    	boolean oldStatus = sync && (!syncNew || (Build.VERSION.SDK_INT < 15));
		boolean faceDetect = true;
		
		boolean root = prefs.getBoolean("root_enabled", false);
		int rootSize = 512;
		
		

		if(FacebookUtil.authorize(context, account)){


			HashMap<String, SyncEntry> localContacts = getLocalContacts(account);
			HashMap<String, Long> names = loadPhoneContacts(context);
			HashMap<String, Long> uids = loadHTCData(context);
			//Log.i("CONTACTS", names.toString());
			boolean phoneOnly = prefs.getBoolean("phone_only", true);
			/*if (phoneOnly){
				names = loadPhoneContacts(context);
			}*/
			boolean wifiOnly = prefs.getBoolean("wifi_only", false);
			boolean syncEmail = prefs.getBoolean("sync_facebook_email", false);
			boolean syncBirthday = prefs.getBoolean("sync_contact_birthday", true);
			boolean force = prefs.getBoolean("force_dl", false);
			boolean google = prefs.getBoolean("update_google_photos", false);
            boolean ignoreMiddleaNames = prefs.getBoolean("ignore_middle_names",false);
            boolean addMeToFriends = prefs.getBoolean("add_me_to_friends", false);
			Log.i("google", String.valueOf(google));
			int fuzziness = Integer.parseInt(prefs.getString("fuzziness", "2"));
			Set<String> addFriends = prefs.getStringSet("add_friends", new HashSet<String>());
			Log.i(TAG, "phone_only: " + Boolean.toString(phoneOnly));
			Log.i(TAG, "wifi_only: " + Boolean.toString(wifiOnly));
			Log.i(TAG, "is wifi: " + Boolean.toString(DeviceUtil.isWifi(context)));
			Log.i(TAG, "phone contacts: " + names.toString()); 
			Log.i(TAG, "using old status api: " +String.valueOf(oldStatus));
            Log.i(TAG, "ignoring middle names : " + String.valueOf(ignoreMiddleaNames));
            Log.i(TAG, "add me to friends : "+  String.valueOf(addMeToFriends));
			boolean chargingOnly = prefs.getBoolean("charging_only", false);
			int maxsize = BitmapUtil.getMaxSize(context);
			File cacheDir = context.getCacheDir();
			Log.i("CACHE DIR", cacheDir.getAbsolutePath());
			Log.i("MAX IMAGE SIZE", String.valueOf(maxsize));
			if (!((wifiOnly && !DeviceUtil.isWifi(context)) || (chargingOnly && !DeviceUtil.isCharging(context)))){
			try {
				if (syncSelf){
					addSelfContact(account, maxsize, cropPhotos, faceDetect, force, root, rootSize, cacheDir, google);
				}	
				//ArrayList<FacebookFQLFriend> friends = FacebookUtil.getFriendInfo(oldStatus);
                List<FacebookGraphFriend> friends = FacebookUtil.getFriends(maxsize, addMeToFriends);
				for (FacebookGraphFriend friend : friends) {
					String uid = friend.getUserName();
					String friendName = friend.getName(ignoreMiddleaNames);
					if (friendName != null && uid != null){
					String match = matches(names.keySet(), friendName , fuzziness);
					
					if (!(phoneOnly && (match == null) && !uids.containsKey(uid)) || addFriends.contains(friendName)){
					//add contact
					if (localContacts.get(uid) == null) {
						//String name = friend.getString("name");
						//Log.i(TAG, name + " already on phone: " + Boolean.toString(names.contains(name)));
						
						addContact(account, friendName, uid);
						
						SyncEntry entry = new SyncEntry();
						Uri rawContactUr = RawContacts.CONTENT_URI.buildUpon()
								.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
								.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
								.appendQueryParameter(RawContacts.Data.DATA1, uid)
								.build();
						Cursor c =mContentResolver.query(rawContactUr, new String[] {
								BaseColumns._ID}, null,
								null, null);
						c.moveToLast();
						long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
						c.close();
					//	Log.i("ID", Long.toString(id));
						entry.raw_id = id;
						localContacts.put(uid, entry);
						if (uids.containsKey(uid)){
							ContactUtil.merge(context, uids.get(uid), id);
						} else if (names.containsKey(match)){
							ContactUtil.merge(context, names.get(match), id);
						}
						//localContacts = loadContacts(accounts, context);
					}
					
	
					// set contact photo
	
					SyncEntry contact = localContacts.get(uid);
					
					updateContactPhoto(contact.raw_id, friend.getPicTimestamp(), maxsize, cropPhotos, friend.getPicURL(), faceDetect, force, root, rootSize, cacheDir, google, imageDefault);
					
					if (syncEmail && !FacebookUtil.RESPECT_FACEBOOK_POLICY)
						ContactUtil.addEmail(context, contact.raw_id, friend.getEmail());


					if (syncLocation  && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
						ContactUtil.updateContactLocation(contact.raw_id, friend.getLocation());
					}
					
					
					if (oldStatus  && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
						ArrayList<Status> statuses = friend.getStatuses();
						if (statuses.size() >= 1){
							updateContactStatus(contact.raw_id,
									statuses.get(0).getMessage(), statuses.get(0).getTimestamp());
						}
						
					}
					if (syncBirthday  && !FacebookUtil.RESPECT_FACEBOOK_POLICY){
						String birthday = friend.getBirthday();
						
						if (birthday != null){
							ContactUtil.addBirthday(contact.raw_id, birthday);
						}
					}
	
				}
				}
			} }catch (Exception e) {
				// TODO: handle exception
				Log.e("ERROR", e.toString());
				e.printStackTrace();
			
			}
			
			if (root){
				try {
					RootUtil.refreshContacts();
				} catch (ShellException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (force){
				SharedPreferences.Editor editor = prefs.edit();
				editor.putBoolean("force_dl", false);
				editor.commit();
	
			}
			
			} else {
				SharedPreferences.Editor editor = prefs.edit();
				editor.putBoolean("missed_contact_sync", true);
				editor.commit();
				}
		}
	}
}