package org.mots.haxsync.utilities;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.mots.haxsync.services.ContactsSyncAdapterService;
import org.mots.haxsync.services.ContactsSyncAdapterService.SyncEntry;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;

public class ContactUtil {
    public static class Contact{
    	public long ID;
    	public String name;
    	public String accountType;
    }
    
    public static class Photo{
    	public byte[] data;
    	public String url;
    	public long timestamp;
    }
    
    public static final String TAG = "ContactUtil";
    
    private static HashMap<String, Drawable> accountIcons = new HashMap<String, Drawable>();
    
    public static Contact getMergedContact(Context c, long contactID, Account account){
    	
		Uri ContactUri = RawContacts.CONTENT_URI.buildUpon()
				.appendQueryParameter(RawContacts.ACCOUNT_NAME, account.name)
				.appendQueryParameter(RawContacts.ACCOUNT_TYPE, account.type)
				.build();
    	
		Cursor cursor = c.getContentResolver().query(ContactUri, new String[] { BaseColumns._ID, RawContacts.DISPLAY_NAME_PRIMARY}, RawContacts.CONTACT_ID +" = '" + contactID + "'", null, null);
		if (cursor.getCount() > 0){
			cursor.moveToFirst();
			Contact contact = new Contact();
			contact.ID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
			contact.name = cursor.getString(cursor.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY));
			cursor.close();
			return contact;
		}
		cursor.close();
		return null;

    }
    
    private static void fillIcons(Context c){
        AccountManager am = AccountManager.get(c);
        AuthenticatorDescription[] auths = am.getAuthenticatorTypes();
        PackageManager pm = c.getPackageManager();
        for (AuthenticatorDescription auth : auths){
        	accountIcons.put(auth.type, pm.getDrawable(auth.packageName,  auth.iconId, null));
        /*	Log.i("Account:", auth.type);
        	Log.i("pkg:", auth.packageName);
        	Log.i("icon:", String.valueOf(auth.smallIconId));*/

        }
    }
    
    
    
    public static List<HashMap<String, Object>> getMergedContacts(Context c, long rawContactID){
    	
    	
		Cursor cursor = c.getContentResolver().query(RawContacts.CONTENT_URI, new String[] { RawContacts.CONTACT_ID}, RawContacts._ID +" = '" + rawContactID + "'", null, null);
		ArrayList<HashMap<String, Object>> contacts = new ArrayList<HashMap<String, Object>>();
		
		if (cursor.getCount() > 0){
			cursor.moveToFirst();
			long contactID = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));
			Cursor c2 = c.getContentResolver().query(RawContacts.CONTENT_URI, new String[] { BaseColumns._ID, RawContacts.DISPLAY_NAME_PRIMARY, RawContacts.ACCOUNT_TYPE}, RawContacts.CONTACT_ID +" = '" + contactID + "'" + " AND " + BaseColumns._ID + " != " +rawContactID , null, null);
			while(c2.moveToNext()){
				HashMap<String, Object> contact = new HashMap<String, Object>();
				contact.put("name", c2.getString(c2.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY)));
				contact.put("id", c2.getString(c2.getColumnIndex(BaseColumns._ID)));
				Drawable icon;
				//todo: cache this shit
				fillIcons(c);
				try{
					icon = accountIcons.get(c2.getString(c2.getColumnIndex(RawContacts.ACCOUNT_TYPE)));
				} catch (Exception e){
					fillIcons(c);
					icon = accountIcons.get(c2.getString(c2.getColumnIndex(RawContacts.ACCOUNT_TYPE)));
				}
				contact.put("icon", icon);
				contacts.add(contact);
			}
			c2.close();

		}
		cursor.close();
		return contacts;

    }

	public static void merge(Context c, long id1, long id2){
		 Log.i("MERGING", id1 +","+id2);
		 ContentValues values = new ContentValues();
	     values.put(ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, id1);
	     values.put(ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, id2);
	     values.put(ContactsContract.AggregationExceptions.TYPE,ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER);
	     c.getContentResolver().update(ContactsContract.AggregationExceptions.CONTENT_URI, values, null, null);
	}
	
	private static Set<Long> getRawContacts(Context c, long contactID, long rawContactID){
		HashSet<Long> ids = new HashSet<Long>();
			Cursor c2 = c.getContentResolver().query(RawContacts.CONTENT_URI, new String[] { BaseColumns._ID}, RawContacts.CONTACT_ID +" = '" + contactID + "'" + " AND " + BaseColumns._ID + " != " +rawContactID , null, null);
			while (c2.moveToNext()){
				ids.add(c2.getLong(c2.getColumnIndex(BaseColumns._ID)));
			}
			c2.close();
		return ids;
	}
	
	public static Set<Long> getRawContacts(ContentResolver c, long rawContactID, String accountType){
		HashSet<Long> ids = new HashSet<Long>();
		Cursor cursor = c.query(RawContacts.CONTENT_URI, new String[] { RawContacts.CONTACT_ID}, RawContacts._ID +" = '" + rawContactID + "'", null, null);	
		if (cursor.getCount() > 0){
			cursor.moveToFirst();
			long contactID = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));
			//	Log.i("QUERY", RawContacts.CONTACT_ID +" = '" + contactID + "'" + " AND " + BaseColumns._ID + " != " +rawContactID + " AND " + RawContacts.ACCOUNT_TYPE + " = '" + accountType+"'");
				Cursor c2 = c.query(RawContacts.CONTENT_URI, new String[] { BaseColumns._ID}, RawContacts.CONTACT_ID +" = '" + contactID + "'" + " AND " + BaseColumns._ID + " != " +rawContactID + " AND " + RawContacts.ACCOUNT_TYPE + " = '" + accountType+"'", null, null);
			//	Log.i("CURSOR SIZE", String.valueOf(c2.getCount()));
				while (c2.moveToNext()){
					ids.add(c2.getLong(c2.getColumnIndex(BaseColumns._ID)));
				}
				c2.close();
		}
		cursor.close();
		return ids;
	}
	
	public static void mergeWithContact(Context c, long rawContactID, long contactID){
		ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
		Set<Long> ids = getRawContacts(c, contactID, rawContactID);
		for (long id: ids){
			ContentProviderOperation.Builder builder = ContentProviderOperation
					.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI);
			builder.withValue(
					ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawContactID);
			builder.withValue(
					ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, id);
			builder.withValue(
					ContactsContract.AggregationExceptions.TYPE,ContactsContract.AggregationExceptions.TYPE_KEEP_TOGETHER);
			operationList.add(builder.build());
		}
		if(operationList.size() > 0)
			try {
				c.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (OperationApplicationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

	}
	
	public static void seperate(Context c, long rawContactID){
		ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
		Cursor cursor = c.getContentResolver().query(RawContacts.CONTENT_URI, new String[] { RawContacts.CONTACT_ID}, RawContacts._ID +" = '" + rawContactID + "'", null, null);
		if (cursor.moveToFirst()){
			long contactID = cursor.getLong(cursor.getColumnIndex(RawContacts.CONTACT_ID));
			Set<Long> ids = getRawContacts(c, contactID, rawContactID);
			for (long id: ids){
				ContentProviderOperation.Builder builder = ContentProviderOperation
						.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI);
				builder.withValue(
						ContactsContract.AggregationExceptions.RAW_CONTACT_ID1, rawContactID);
				builder.withValue(
						ContactsContract.AggregationExceptions.RAW_CONTACT_ID2, id);
				builder.withValue(
						ContactsContract.AggregationExceptions.TYPE,ContactsContract.AggregationExceptions.TYPE_KEEP_SEPARATE);
				operationList.add(builder.build());
			}
			
			if(operationList.size() > 0)
				try {
					c.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (OperationApplicationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
		cursor.close();
		}
	
	public static Photo getPhoto(ContentResolver c, long rawContactId){
		Photo photo = new Photo();
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";



		Cursor c1 = c.query(ContactsContract.Data.CONTENT_URI, new String[] {ContactsContract.CommonDataKinds.Photo.PHOTO, ContactsContract.Data.SYNC2, ContactsContract.Data.SYNC3 }, where , null, null);
		if (c1.getCount() > 0){
			c1.moveToLast();
			photo.data = c1.getBlob(c1.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
			photo.timestamp = Long.valueOf(c1.getString(c1.getColumnIndex(ContactsContract.Data.SYNC2)));
			photo.url = c1.getString(c1.getColumnIndex(ContactsContract.Data.SYNC3));
		}
		c1.close();
		return photo;
	}
	
	public static void updateContactPhoto(ContentResolver c, long rawContactId, Photo pic, boolean primary){
		ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
		

		
		//insert new picture
		try {
			if(pic.data != null) {
                //delete old picture
                String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId
                        + "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
                Log.i(TAG, "Deleting picture: "+where);

                ContentProviderOperation.Builder builder = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI);
                builder.withSelection(where, null);
                operationList.add(builder.build());
				builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
				builder.withValue(ContactsContract.CommonDataKinds.Photo.RAW_CONTACT_ID, rawContactId);
				builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
				builder.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, pic.data);
				builder.withValue(ContactsContract.Data.SYNC2, String.valueOf(pic.timestamp));
				builder.withValue(ContactsContract.Data.SYNC3, pic.url);
                if (primary)
				    builder.withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
				operationList.add(builder.build());

				
			}
			c.applyBatch(ContactsContract.AUTHORITY,	operationList);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			Log.e("ERROR:" , e.toString());
		}


	}
	
	public static void removeBirthdays(Context c, long rawContactId){
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
				+ "' AND " + ContactsContract.CommonDataKinds.Event.TYPE + " = '" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + "'";
		c.getContentResolver().delete(ContactsContract.Data.CONTENT_URI, where, null);
	}
	
	public static void removeEmails(Context c, long rawContactId){
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE+ "'";
		c.getContentResolver().delete(ContactsContract.Data.CONTENT_URI, where, null);
	}
	
	public static void addEmail(Context c, long rawContactId, String email){
		DeviceUtil.log(c, "adding email", email);
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE+ "'";
		Cursor cursor = c.getContentResolver().query(ContactsContract.Data.CONTENT_URI, new String[] { RawContacts.CONTACT_ID}, where, null, null);
		if (cursor.getCount() == 0){
			ContentValues contentValues = new ContentValues();
			//op.put(ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID, );
			contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
			contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
			contentValues.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
			c.getContentResolver().insert(ContactsContract.Data.CONTENT_URI, contentValues);
		}
		cursor.close();

	}

	public static void addBirthday(long rawContactId, String birthday){
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
				+ "' AND " + ContactsContract.CommonDataKinds.Event.TYPE + " = '" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + "'";
		Cursor cursor = ContactsSyncAdapterService.mContentResolver.query(ContactsContract.Data.CONTENT_URI, null, where, null, null);
		int count = cursor.getCount();
		cursor.close();
		if (count <= 0){
			ContentValues contentValues = new ContentValues();
			contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
			contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
			contentValues.put(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY);
			contentValues.put(ContactsContract.CommonDataKinds.Event.START_DATE, birthday);
			
			try {
				ContactsSyncAdapterService.mContentResolver.insert(ContactsContract.Data.CONTENT_URI, contentValues);
			//	mContentResolver.applyBatch(ContactsContract.AUTHORITY,	operationList);
			} catch (Exception e) {
				e.printStackTrace();
				//Log.e("ERROR:" , e.^);
			}
		}
	}

	public static void removeContactLocations(Context c, Account account){
		ContactsSyncAdapterService.mContentResolver = c.getContentResolver();
		HashMap<String, ContactsSyncAdapterService.SyncEntry> localContacts = ContactsSyncAdapterService.getLocalContacts(account);
		for (ContactsSyncAdapterService.SyncEntry s : localContacts.values()){
			ContactsSyncAdapterService.mContentResolver.delete(ContactsContract.Data.CONTENT_URI, ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE + "' AND " + ContactsContract.Data.RAW_CONTACT_ID + " = " + s.raw_id, null); 
		}			
		
	}

	public static void updateContactLocation(long rawContactId, String country, String region, String city){
		if ((country == null || country.equals("")) && (region == null || region.equals("")) && (city == null || city.equals(""))){
			return;
		}
		String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId 
				+ "' AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE + "'";
		String[] projection = {ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, ContactsContract.CommonDataKinds.StructuredPostal.REGION, ContactsContract.CommonDataKinds.StructuredPostal.CITY};
		
		Cursor cursor = ContactsSyncAdapterService.mContentResolver.query(ContactsContract.Data.CONTENT_URI, projection, where, null, null);
		boolean insert = false;
		if (cursor.getCount() == 0){
			insert = true; 
		} else{
			cursor.moveToFirst();
			String oldCountry = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY));
			String oldRegion = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION));
			String oldCity = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY));
			if ((oldCountry != null && !oldCountry.equals(country)) || (oldRegion != null && !oldRegion.equals(region)) || (oldCity != null && oldCity.equals(city))){
				ContactsSyncAdapterService.mContentResolver.delete(ContactsContract.Data.CONTENT_URI, where, null);
				insert = true;
			}
		}
		cursor.close();
		if (insert){
			ContentValues contentValues = new ContentValues();
			//op.put(ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID, );
			contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
			contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
			if (country != null && ! country.equals("")){
				contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, country);
			} if (region != null && ! region.equals("")){
			contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, region);
			} if (city != null && ! city.equals("")){
			contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, city);
			}
			try {
				ContactsSyncAdapterService.mContentResolver.insert(ContactsContract.Data.CONTENT_URI, contentValues);
			//	mContentResolver.applyBatch(ContactsContract.AUTHORITY,	operationList);
			} catch (Exception e) {
				e.printStackTrace();
				//Log.e("ERROR:" , e.^);
			}
		}
	
	}

    public static void updateContactLocation(long rawContactId, String location){
        if ((location == null || location.equals(""))){
            return;
        }
        String where = ContactsContract.Data.RAW_CONTACT_ID + " = '" + rawContactId
                + "' AND " + ContactsContract.Data.MIMETYPE + " = '" + StructuredPostal.CONTENT_ITEM_TYPE + "'";
        String[] projection = {StructuredPostal.FORMATTED_ADDRESS};

        Cursor cursor = ContactsSyncAdapterService.mContentResolver.query(ContactsContract.Data.CONTENT_URI, projection, where, null, null);
        boolean insert = false;
        if (cursor.getCount() == 0){
            insert = true;
        } else{
            cursor.moveToFirst();
            String oldloc = cursor.getString(cursor.getColumnIndex(StructuredPostal.FORMATTED_ADDRESS));
            if ((oldloc == null) || (!oldloc.equals(location))){
                ContactsSyncAdapterService.mContentResolver.delete(ContactsContract.Data.CONTENT_URI, where, null);
                insert = true;
            }
        }
        cursor.close();
        if (insert){
            ContentValues contentValues = new ContentValues();
            //op.put(ContactsContract.CommonDataKinds.StructuredPostal.CONTACT_ID, );
            contentValues.put(ContactsContract.Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
            contentValues.put(StructuredPostal.FORMATTED_ADDRESS, location);
            try {
                ContactsSyncAdapterService.mContentResolver.insert(ContactsContract.Data.CONTENT_URI, contentValues);
                //	mContentResolver.applyBatch(ContactsContract.AUTHORITY,	operationList);
            } catch (Exception e) {
                e.printStackTrace();
                //Log.e("ERROR:" , e.^);
            }
        }

    }
	

}