function writeToDB(fname, argsArray, callback, bypassQueue) {
	var functions_using_post, functions_modifying_the_segment;
	if (window.segmentFlags) { // keep track of running ajax calls
		if (!segmentFlags.ajaxCalls) segmentFlags.ajaxCalls = 1;
		else segmentFlags.ajaxCalls++;
	}
	
	var argsAsJSON = JSON.stringify(argsArray);
	var server_url = bypassQueue?MESSAGE_QUEUER_BYPASS_URL:MESSAGE_QUEUER_BASE_URL;
	var url = server_url+"&fn="+fname+"&fa="+argsAsJSON;
	var callback_wrapper = (function(callback, fname) {
		return function(data) {
			if (callback) {
				callback(data);
			}
			if (segmentFlags && segmentFlags.ajaxCalls && segmentFlags.ajaxCalls > 0) {
				segmentFlags.ajaxCalls--;
			}
		}
	}) (callback, fname);
	functions_using_post = ['relayCurl', 'addDataInBulkFromWizard', 'deletePoints', 'addPointsToSegment', 'createPhotobook'];
	if (in_array(fname, functions_using_post)) {
		jx.load(url, callback_wrapper, '', 'POST');
	} else {
		jx.load(url, callback_wrapper);
	}
	
	// update segment modified time only send command at most once every 5 seconds - [fname != 'editSegment']
	if (segmentData) {
		var segment_id = segmentData.id;
		if (window.memoryCreationWizard) {
			segment_id = memoryCreationWizard.sid;
		}
		functions_modifying_the_segment = ['createPoint','editPoint','deletePoint',
			'editMedia','addUsersToSegment','removeUsersFromSegment', 'createTag',
			'deleteTag', 'unpairUsersAndPoint'];
		if (segment_id && segmentFlags && !segmentFlags.updated && in_array(fname, functions_modifying_the_segment)) {
			updateSegmentModified();
			segmentFlags.updated = 1;
			clearStalledAjaxCount();
			setTimeout(function () {
				updateSegmentModified();
				segmentFlags.updated = 0
			}, 3000);
		}
	}
	
	// track writes to db
	if (typeof(trackSave) == 'function' && window.loggedInUser) {
		trackSave(loggedInUser);
	}
}

function readFromDB(fname, argsArray, callback, no_cache) {
	var argsAsJSON = JSON.stringify(argsArray);
	var url = CACHED_DATABASE_READER_BASE_URL+"&fn="+fname+"&fa="+argsAsJSON;
	if (fname == 'getLocations' || no_cache) url += '&cache=false'; // clear get location cache on the client side
	jx.load(url, callback,'','POST');
}

function apiCall(fn, args, callback) {
	var argsAsJson = JSON.stringify(args),
		url = API_BASE_URL+"?fn="+fn+"&fa="+argsAsJson;
	
	jx.load(url, callback,'','GET');
}

function createLocation (user_id, location_name, callback) {
	writeToDB('createLocation', [{'user_id':user_id, 'name':location_name}], callback);
}

function editSegment (sid, segment_args, callback) {
	writeToDB('editSegment', [segment_args, sid], callback)
}

function getFacebookUserByRmnId (user_id, callback) {
	readFromDB('getFacebookUserIdByRmnId', [user_id], callback);
}

function getLocations (location_id, callback) {
	readFromDB('getLocations', [location_id], callback);
}

function getMedia (media_id, callback) {
	readFromDB('getMedia', [media_id], callback);
}

function getMediaByPoints (points, callback) {
	readFromDB("getMediaByPoints", [points], callback);
}

function getMusicPointsByUser (users, start, end, callback) {
	readFromDB('getMusicPointsByUser', [users, start, end], callback);
}

function getTagsByObject (args, callback) {
	readFromDB('getTagsByObject', [args], callback);
}

function getSegmentPaginated (sid, start_index, count, types, callback) {
	var args = {
			"sid": sid,
			"startIndex": start_index,
			"count": count
		},
		function_name = 'getSegmentPaginated';
		
	if ((types != null) && (types.length > 0)) {
		args["types"] = types;
	}
	
	if (window.has_segment_point_table) {
		function_name += 'FromSegmentPointTable';
	}
	
	apiCall(function_name, args, callback);
}

function updateSegmentModified() {
	if (segmentData) {
		var segment_id = segmentData.id;
		if (window.memoryCreationWizard) {
			segment_id = memoryCreationWizard.sid;
		}
		if (segment_id) {
			writeToDB('editSegment', [{'utcLastModifiedSec':1, 'dup':new Date().getTime()}, segment_id]);
			setTimeout(function () {
				jx.load('?p=slideshowJSON&sid='+segment_id+'&cache=true');
			}, 2000);
		}
	}
}

function clearStalledAjaxCount() {
	// clear ajax call count if it's frozen for too long
	if (segmentFlags.ajaxCalls && !segmentFlags.ajaxCallsClear) {
		segmentFlags.ajaxCallsClear = setTimeout('if (segmentFlags.ajaxCalls == "'+segmentFlags.ajaxCalls+'") { segmentFlags.ajaxCalls = 0; } segmentFlags.ajaxCallsClear = null; clearStalledAjaxCount();', 10000);
	}
}

function trackActivation(){
	var app_id;
	if (window.kaptur_quickstart && kaptur_quickstart.app_id) app_id = kaptur_quickstart.app_id;
	else if (window.KML && KML.app_id) app_id = KML.app_id;
	else if (window.rmnAppId) app_id = rmnAppId;
	gaIframe('activation', {'app_id':app_id});
	/*var a  = document.createElement('script'); 
	a.type = 'text/javascript'; 
	a.async = true;
    a.src = "https://secure.media6degrees.com/orbserv/hbjs?pixId=8362&pcv=55";
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(a, s);*/
}

function loadRmnUserInfo(initFn) {
	if (!dataFlags.offlineView || dataFlags.offlineBypass) {
		readFromDB('getRmnUserInfoByFacebookId', [loggedInUser.toString()], function(data) {
			var result = JSON.parse(data);
			result = result['result'];
			if (result && result['user_id']) {
				if (!userProfileObj.id) {
					userProfileObj.id = result['user_id'];
					userProfileObj.first_name = urldecode(result['firstName']);
					userProfileObj.last_name = urldecode(result['lastName']);
					userProfileObj.email = urldecode(result['emailAddress']);
					userProfileObj.thumbnail = 'http://graph.facebook.com/'+loggedInUser+'/picture'; // urldecode(result['thumb']);
					userProfileObj.gender = result['gender']=='not_set'?'':result['gender'];
					userProfileObj.app_id = result['app_id'];
					userProfileObj.locale = result['locale'];
				}
				
				welcomeRmnUser(initFn);
			} else {
				var fbid = loggedInUser.toString();
				var email_login = $.cookies.get("emailLoginId");
				var email_addr, user_id;
				if (email_login) {
					try {
						//email_login = JSON.parse(email_login);
						email_addr = email_login[0];
						user_id = email_login[1];
					} catch(err) {}
				} // consolidate logged in user with user id of email activation
				if (user_id) {
					// make sure that there is no existing fb service id for this rmn id before adding a new one
					readFromDB('getFacebookUserIdByRmnId', [user_id], function(data) {
						var existing_fbid = JSON.parse(data);
						existing_fbid = existing_fbid['result'];
						if (!existing_fbid) {
							writeToDB('addUserServiceByFacebookId', [{'user_id':user_id}, fbid]);
							userProfileObj.email = email_addr;
							welcomeNewRmnUser(user_id, initFn);
						} else addUserByFbId(fbid, initFn);
						trackActivation();
					});
				} else {
					addUserByFbId(fbid, initFn);
					trackActivation();
				}
				// flag increment vote count
				if (window.memoryCreationWizard) {
					memoryCreationWizard.incrementVoteCount = 1;
				}
			}
		});
	} //else location.href = location.href;
}

function addUserEmailAddress(emailAddress){
	var fn = "addUserEmailAddress";
	var fa = [{"emailAddress":emailAddress,"user_id":userProfileObj.id,"app_id":memoryCreationWizard.app_id}];
	writeToDB(fn,fa,null,false);
}

function addUserByFbId(fbid, initFn) {
	writeToDB('addRmnUserByFacebookId', [fbid], function(data) {
		var user_id = extractJSONid(data);
		welcomeNewRmnUser(user_id, initFn);
		trackActivation();
	});
}

function welcomeNewRmnUser(user_id, initFn) {
	userProfileObj.id = user_id;
	welcomeRmnUser(initFn);
	
	// update the appId if it's not regular rmn. dependency on js in header.php.  this is bad spaghetti code and doesn't respect function encapsulation but i am sleepy.
	if (rmnAppId) writeToDB("setRmnUserInfo",[{"app_id":rmnAppId},userProfileObj.id]);//>1
}

function loadRmnSegment(ignoreSegmentId) {
	// do not load again if night is already loaded in offline mode
	if (dataFlags.offlineView) return;
	
	// init variables
	segmentData = {};
	if (!fbPhotoPointIds) fbPhotoPointIds = {};
	if (!fbVideoPointIds) fbVideoPointIds = {};
	if (!flickrPhotoPointIds) flickrPhotoPointIds = {};
	if (!rmnPoints) rmnPoints = {};
	if (!rmnPointTimes) rmnPointTimes = {};
	if (!rmnPointFriendFilters) rmnPointFriendFilters = {};
	if (!segmentPairingIds) segmentPairingIds = [];
	if (!segmentFriendFbIds) segmentFriendFbIds = {};
	segmentFriendIds = [];
	if (!segmentFbPosts) segmentFbPosts = {};
	if (!segmentFlags) segmentFlags = {};
	
	// if segment id is provided, use that, otherwise use sts
	if (getSegment && getSegment.match(/^\w{64}$/) && !ignoreSegmentId) {
		readFromDB('getSegment', [getSegment.toString()], function(data) {
			try {
				var result = JSON.parse(data);
				var rmn_segment = result['result'];
				if (rmn_segment && rmn_segment != '') {
					segmentFlags.segmentLoadedById = 1;
					loadRmnSegmentPoints(rmn_segment);
				} else if (getSts && getFid) {
					loadRmnSegment(1); // attempt to retrieve segment data using time range
				} else {
					showError('Sorry, we couldn\'t find any memories associated with this link.'.replace(/ /g, '&nbsp;')+'<br>Click <a href="?p=nw">here</a> to recreate a memory now!');//p=create
					// showError('No public nights found!');
				}
			} catch(err) {
				// for new memories
				updateTabStatus('photos');
				updateTabStatus('friends');
				updateTabStatus('statuses');
			}
		});
	} else {
		var segment_start = getSts;
		var segment_tzoffset = -new Date(getSts*1000).getTimezoneOffset()/60;
		if (!segment_start || location.href.indexOf('newcreator=1') != -1) showNewNightHints();
		if (!segment_start) {
			// load start time to today
			segment_start = new Date();
			segment_start.setHours(0, 0, 0, 0);
			segment_start = segment_start.getTime() / 1000;
		}var segment_end = getEts? getEts : segment_start+36*60*60;
		segmentData = {'start':segment_start, 'end':segment_end, 'tzoffset':segment_tzoffset};
		
		// determine whether to display night of logged in user or of friend
		var logOwner = loggedInUser;
		if (editNight) logOwner = getFid;
		
		if (logOwner && !segmentFlags.newNight) {
			// get log owner rmn id
			readFromDB('getRmnUserInfoByFacebookId', [logOwner.toString()], function(data) {
				var result = JSON.parse(data);
				result = result['result'];
				if (result) {
					var rmnid = result['user_id'];
					segmentData.owner = rmnid;
					loadRmnSegmentFromDB(rmnid, segment_start, segment_end, segment_tzoffset);
				}
			});
		} else {
			segmentData = {'start':segment_start, 'end':segment_end, 'tzoffset':segment_tzoffset, 'location':{}, 'cover':{}, 'privacy':{}, 'tags':{}};
			$(document).ready(function() {
				updateDateDisplays();
				updateNightInfo();
				showContributeElements();
			});
			//showError('Please <a href="javascript:loginToFacebook()">sign in</a> to create night!');
			//showNewNightHints();
		}
	}
}

function loadRmnSegmentFromDB(rmnid, start_time, end_time, timezone_offset, search_params) {
	var search_start = start_time;
	var search_end = end_time;
	if (search_params) {search_start = search_params.start;search_end = search_params.end;}
	readFromDB('getSegments', [rmnid, search_start, search_end], function(response) {
		response = JSON.parse(response);
		if (response['status'] == "ok") {
			var rmn_segments = response['result'];
			if (rmn_segments && rmn_segments.length) {
				// if there is only one segment, load it, otherwise, present list to user
				if (rmn_segments.length == 1 && getSegment || rmnid != userProfileObj.id) loadRmnSegmentPoints(rmn_segments[0]);
				else showSegmentsHTML(rmn_segments, 'choose_segment');
			} else if (!editNight && !dataFlags.offlineView) {
				createRmnSegment(rmnid, start_time, end_time);
			} else {
				segmentData = {'start':start_time, 'end':end_time, 'tzoffset':timezone_offset, 'location':{}, 'cover':{}, 'privacy':{}, 'tags':{}};(document).ready(function() {updateDateDisplays();});
				showError('Sorry, we couldn\'t find any memories associated with this link.<br>Click <a href="?p=nw">here</a> to recreate a memory now!');//p=create
				// showError('No public nights found!');
			}
		}
	});
}

function createRmnSegment(rmnid, start_time, end_time) {
	// create new location :: 'name', 'thumb', 'description', 'partnerId_id':2, 'partnerIdValue'
	writeToDB('createLocation', [{'user_id':userProfileObj.id, 'name':''}], (function(start_time, end_time) {
		return function(data) {
			var location_id = extractJSONid(data);
			
			// create new segment
			var user_tzoffset = -new Date(start_time*1000).getTimezoneOffset()/60;
			var segment_privacy = {'view':'vli', 'contribute':'cfr', 'autoimport':true, 'value':'public'};
			var segment_privacy_ids = 'vli,cfr';//'vpb,cfr';
			writeToDB('createSegment', [{'user_id':userProfileObj.id, 'utcStartSec':start_time, 'utcEndSec':end_time, 'location_id':location_id, 'timezoneOffset':user_tzoffset, 'privacy':segment_privacy.value, 'privacy_ids':segment_privacy_ids}],
			(function (start_time, end_time, location_id, user_tzoffset, segment_privacy) {
				return function(data) {
					var segment_id = extractJSONid(data);
					// store segment data in memory
					segmentData = {'id':segment_id, 'start':start_time, 'end':end_time, 'title':'', 'desc':'', 'owner':userProfileObj.id, 'fbOwner':loggedInUser, 'location':{'id':location_id}, 'tzoffset':user_tzoffset, 'privacy':segment_privacy, 'cover':{}}
					segmentFlags.newNight = 1;
					
					// update date displays and night info
					updateDateDisplays();
					if (getEventId) {
						segmentData.location.eid = getEventId;
						segmentData.location.id = location_id;
						//query event
						queryFacebook('SELECT eid, name, pic_small, location, venue FROM event WHERE eid={0}',
							[getEventId],
							function(data) {
								var event = data[0];
								segmentData.location.name = urldecode(event['name']);
								segmentData.location.desc = urldecode(event['location']);
								segmentData.location.city = urldecode(event['venue']['city']);
								segmentData.location.thumb = event['pic'];
								var editLocationParams = {};
								var event_name = d_escape(segmentData.location.name);
								editLocationParams['name'] = event_name;
								editLocationParams['description'] = d_escape(segmentData.location.desc);
								editLocationParams['city'] = d_escape(segmentData.location.city);
								editLocationParams['partnerId_id'] = 2;
								editLocationParams['partnerIdValue'] = segmentData.location.eid;
								editLocationParams['thumb'] = d_escape(segmentData.location.thumb);
								writeToDB('editLocation', [editLocationParams, segmentData.location.id]);
								writeToDB('editSegment', [{'title':event_name}, segmentData.id]);
								updateNightInfo();

								// auto add event members
								// query event members
								var event_members = {
									fql: 'SELECT uid, eid, rsvp_status from event_member WHERE eid = {0} AND rsvp_status = "attending" AND uid IN (SELECT uid2 FROM friend WHERE uid1={1})',
									args: [event['eid'], loggedInUser]
								};
								var event_member_names = {
									fql: 'SELECT uid, first_name, last_name FROM user WHERE uid IN (SELECT uid FROM {0})',
									args: [event_members]
								};
								multipleQueryFacebook([event_members, event_member_names], function() {
									event_members = event_members.value;
									event_member_names = event_member_names.value;
									// generate fb names hash
									var event_member_names_list = {};
									if (event_member_names && event_member_names.length) {
										for (var i=0; i<event_member_names.length; i++) {
											var user_info = event_member_names[i];
											event_member_names_list[user_info['uid']] = [user_info['first_name'], user_info['last_name']];
										}
									} // process event members list
									if (event_members && event_members.length) {
										var event_id = event_members[0]['eid'];
										event_suggestions_list[event_id] = {'members':{}};
										for (var i=0; i<event_members.length; i++) {
											var event_member = event_members[i]['uid'];
											var event_member_name = event_member_names_list[event_member];
											var event_member_firstname = event_member_name[0];
											var event_member_lastname = event_member_name[1];
											event_suggestions_list[event_id]['members'][event_member] = [event_member_firstname, event_member_lastname];
											if (i<20 && !document.getElementById('attendee'+event_member) && event_member != loggedInUser) addFbUserToNight(event_member, 0, event_member_firstname, event_member_lastname);
										}
									}
								}); // end multipleQueryFacebook
							}
						); // end queryFacebook
					} else updateNightInfo();
					showContributeElements();
					
					// show night owner in attendee list by default
					addToAttendList(loggedInUser);
					
					// show first save hint
					checkFirstSave();
					
					// show first time create hint
					document.getElementById('newNightCreateHintsLink').style.display = 'inline';
					checkFirstCreate();
					
					// load segment points
					loadRmnPointsFromDB(rmnid, start_time, end_time);
				}
			}) (start_time, end_time, location_id, user_tzoffset, segment_privacy));
		}
	}) (start_time, end_time));
}

function loadRmnSegmentPoints(rmn_segment) {
	var segment_start = rmn_segment['utcStartSec'];
	var segment_end = rmn_segment['utcEndSec'];
	var segment_tzoffset = rmn_segment['timezoneOffset'];
	var segment_privacy = rmn_segment['privacy'];
	var segment_owner = rmn_segment['user_id'];
	var segment_privacy_ids = parsePrivacyIds(rmn_segment['privacy_ids']);
	var segment_view_privacy = segment_privacy_ids['view'];
	var segment_contribute_privacy = segment_privacy_ids['contribute'];
	var segment_auto_import_privacy = segment_privacy_ids['autoimport'];
	// init segment data object
	segmentData = {'start':segment_start, 'end':segment_end, 'tzoffset':segment_tzoffset, 'privacy':{'view':segment_view_privacy, 'contribute':segment_contribute_privacy, 'autoimport':segment_auto_import_privacy, 'value':segment_privacy}};
	segmentData.owner = segment_owner;
	
	// udpate edit night flag if segment was loaded by segment id
	if (segmentFlags.segmentLoadedById && segment_owner != userProfileObj.id) {
		editNight = 1;
	} else editNight = 0;
	
	// enforce view privacy and show and process contribute elements subsequently
	if (segment_view_privacy == 'vpr' && editNight) {
		showLoginPrompt('', 1); // showError('This night is only viewable by the night\'s owner.'+(!loggedInUser?'<br>If you are the owner, <a href="javascript:loginToFacebook()">sign in</a>.':''));
		//showError('No public nights found!');
	} else {
		if (dataFlags.offlineView) {
			updateDateDisplays(); // show segment date
			// do not render private nights
			if (segment_view_privacy == 'vli' || segment_view_privacy == 'vfr') {
				var msg = '';
				if (segment_view_privacy == 'vfr') msg = 'Only friends can view this memory. ';
				showLoginPrompt(msg); // showError('This is a private night. '+msg);
				// loginToFacebook(); // show login prompt
				if (segment_view_privacy == 'vli' && $('#pageTabWrapper #photosTab').length) {
					loadViewableRmnSegment(rmn_segment);
				}
			} else {
				loadViewableRmnSegment(rmn_segment);
			}
		} else {
			if (segment_view_privacy == 'vfr' && editNight) {
				if (segmentFlags.segmentLoadedById) {
					readFromDB('getFacebookUserIdByRmnId', [segment_owner], function(data) {
						var result = JSON.parse(data);
						var owner_fbid = result['result'];
						if (owner_fbid) {
							checkFbFriendsForView(rmn_segment, owner_fbid)
						}
					});
				} else {
					checkFbFriendsForView(rmn_segment, getFid);
				}
			} else {
				loadViewableRmnSegment(rmn_segment);
			}
		}
	}
}

function getFacebookUserIdByRmnId (rmnId, callback) {
	readFromDB('getFacebookUserIdByRmnId', [rmnId], callback);
}

function showContributeElements() {
	if (segmentData.privacy) {
		var contribute_privacy = segmentData.privacy.contribute;
		if (contribute_privacy == 'cfr' && editNight) {
			if (!dataFlags.offlineView) {
				if (segmentFlags.segmentLoadedById) {
					readFromDB('getFacebookUserIdByRmnId', [segmentData.owner], function(data) {
						var result = JSON.parse(data);
						var owner_fbid = result['result'];
						if (owner_fbid) {
							checkFbFriendsForContribute(owner_fbid);
						}
					});
				} else {
					checkFbFriendsForContribute(getFid);
				}
			} else {
				showContributeElementsValidated(1);
			}
		} else if (contribute_privacy == 'cli' || !editNight) {
			showContributeElementsValidated(1);
		} else {
			segmentFlags.lockContribute = 1;
		}
	} else {
		showContributeElementsValidated(1);
	}
	showNewNightDiaryText(); // determine whether to show new night text
}

function checkFbFriendsForContribute(owner_fbid) {
	if (segmentFlags.viewerIsFriend == null) {
		var isFriendsFQL = buildIsFriendFQL(owner_fbid);
		queryFacebook(isFriendsFQL.fql, isFriendsFQL.args, function(data) {
			if (data && data.length) {
				segmentFlags.viewerIsFriend = 1;
				showContributeElementsValidated(1);
			} else {
				segmentFlags.viewerIsFriend = 0;
				showContributeElementsValidated();
			}
		});
	} else if (segmentFlags.viewerIsFriend) showContributeElementsValidated(1);
	else showContributeElementsValidated();
}

function showContributeElementsValidated(perms) {
	var elems = contributeElements;
	if (wizardMemoryData && !segmentFlags.wizardShowContributeActive) elems = contributeSavingElements;
	for (var i in elems) {
		// convert buttons to login handlers
		if (dataFlags.offlineView && segmentData.id) {
			if (i != 'nightCanvasAddMedia') {
				var elem = document.getElementById(i);
				if (elem) elem.onclick = (function(i) {return function() {
					if (i == 'attendBtn') loginToFacebook(function() {propagateContributeAction(elems[i])});
					else {
						var contributeAction = elems[i];
						var msg = 'Please <a href="javascript:loginToFacebook('+(contributeAction?'function() { propagateContributeAction(\''+contributeAction+'\') }':'')+')">sign in</a> to contribute.'
						if (segmentData.privacy && segmentData.privacy.contribute == 'cfr') msg += ' Only friends can contribute to this memory.';
						showError(msg);// loginToFacebook();
					}
				}}) (i);
			}
		}
		
		// show contribute elements
		if (perms && !in_array(i, ['attendBtn', 'addVideosBtn', 'nightVideosAdd', 'addCanvasMusicBig', 'addCanvasMusicSmall'])) {
			var contributeElement = document.getElementById(i);
			if (contributeElement) {
				var display_style = 'block';
				if (in_array(i, ['retroDiaryEmptyLink', 'retroDiaryAddLink', 'nightFriendsAdd', 'filterMediaByPersonReload'])) display_style = 'inline'; // for inline elements
				contributeElement.style.display = display_style;
			}
		}
	}
	
	// init colorbox elements
	if (!dataFlags.offlineView || !segmentData.id) initContributeElements();
	
	if (perms) {
		// enable fb event thumb and calendar icon click handlers
		if (userProfileObj.id == segmentData.owner) {
			/*initColorbox('nightSummaryThumb, #nightCalendarStartWrapper, #nightCalendarEndWrapper, #nightCalendarWrapper', 'nightSummaryEditWrapper');
			enableEditSummary('nightSummaryThumb');
			enableEditSummary('nightCalendarStartWrapper');
			enableEditSummary('nightCalendarEndWrapper');
			enableEditSummary('nightCalendarWrapper');*/
			initColorbox('nightSummaryWrapper', 'nightSummaryEditWrapper');
			enableEditSummary('nightSummaryWrapper');
		}
	} else segmentFlags.lockContribute = 1;
	segmentFlags.contribute = perms;
	if (segmentFlags.enable_drag_and_drop/*segmentFlags.contribute*/) {
		enableDragAndDrop();
		segmentFlags.enable_drag_and_drop = 0;
	}
}

function enableEditSummary(div_id) {
	var nightSummaryEdit = document.getElementById(div_id);
	if (nightSummaryEdit) {
		nightSummaryEdit.onmouseover = function() {loadFbEvents();}
		nightSummaryEdit.onclick = function() {editNightSummary();}
		nightSummaryEdit.style.cursor = 'pointer';
	}
}

function checkFbFriendsForView(rmn_segment, owner_fbid) {
	var isFriendsFQL = buildIsFriendFQL(owner_fbid);
	queryFacebook(isFriendsFQL.fql, isFriendsFQL.args, function(data) {
		if (data && data.length) {
			segmentFlags.viewerIsFriend = 1;
			loadViewableRmnSegment(rmn_segment);
		} else {
			segmentFlags.viewerIsFriend = 0;
			var msg = 'Only friends can view this memory. ';
			showLoginPrompt(msg); // showError('This is a private night. Only friends can view this night.');
		}
	});
}

function loadViewableRmnSegment(rmn_segment) {
	var segment_id = rmn_segment['id'], url_params = getUrlParams();
	segmentData['id'] = segment_id;
	loadSegmentMusic();
	
	// start slideshow if user is coming from a shared link
	var autoStartSlideshow = (in_array(url_params['ref'], ['link','facebook','twitter','email','featured','recent','nf','friend_post'])) && !display_photo_on_load && !document.getElementById('photosTab');
	if (autoStartSlideshow && (document.getElementById('nightCanvasRow').childNodes.length > 0)) {
		viewAsSlideShow(function() {
			loadViewableRmnSegmentDelayed(rmn_segment);
		});
	} else {
		loadViewableRmnSegmentDelayed(rmn_segment);
	}
}

function loadSegmentMusic() {
	// load first music
	var videoThumbRow = document.getElementById('videoThumbRow');
	if (videoThumbRow) {
		var nightMusicItems = videoThumbRow.childNodes;
		if (nightMusicItems.length && !document.getElementById('videoPlayerWrapper').innerHTML) {
			try {document.getElementById(nightMusicItems[0].id.replace('_wrapper', '')).onclick();}
			catch (err) {};
		}
	}
	
	// load segment music
	readFromDB('getMusicPointsByUser', [[segmentData.owner], segmentData.start, segmentData.end], function(response) {
		response = JSON.parse(response);
		if (response['status'] == "ok") {
			var segment_music = response['result'];
			loadRmnPoints(segment_music, 1);
		}
	});
}

function loadPaginatedData(start_index) {
	var getPointRepresentation = function (data) {
		var point = {},
			type = data.type;
		data = data.metadata;
		point.id = data.rmnPointId;
		point.user_id = data.rmnOwnerId;
		point.description = data.rmnPointDesc;
		point.partnerId_id = data.rmnPointPartnerIdId;
		point.timezoneOffset = data.timezoneOffset;
		switch (type) {			
			case "facebookLink":
			case "facebook":
				point.partnerIdValue = '{"actor_id":"'+data.actorid+'","target_id":"'+data.targetid+'","post_id":"'+data.postid+'"}';
				point.description = data.message;
				break;
				
			default:
				point.partnerIdValue = data.rmnPointPartnerIdValue;
				break;
		}
		point.utcTimeSec = data.rmnPointUtcTimeSec;
		
		return point;
	}, getMediaRepresentation = function (data) {
		var media = {},
			type = data.type;
		data = data.metadata;
		media.media_id = data.rmnMediaId;
		media.point_id = data.rmnPointId;
		media.alt_src = data.alt_src;
		switch (type) {
			case "photo":
				media.partnerIdValue = data.photoid;
				break;
			case "video":
				media.partnerIdValue = data.videoid;
				break;
			case "music":
				media.partnerIdValue = data.musicid;
				break;
		}
		
		media.mediaType_id = MEDIA_TYPES[type];
		media.title = data.rmnPointDesc;
		media.description = data.rmnMediaDesc;
		media.thumb = data.thumb;
		media.width = data.width;
		media.height = data.height;
		media.src = data.src;
		media.url = data.url;
		media.utcTimeSec = data.utcTimeSec;
		media.partnerId_id = data.rmnPointPartnerIdId;
		media.user_id = data.rmnPointPartnerIdValue;
		
		return media;
	}, getMediaTags = function (data) {
		var tags = {},
			i, j, item, tag_set, tag;
		
		for (i = 0; i < data.length; i++) {
			item = data[i].metadata;
			tag_set = data[i].tags;
			if (tag_set) {
				for (j = 0; j < tag_set.length; j++) {
					tag = tag_set[j];
					tag.objectIdValue = item.rmnMediaId;
					tag.objectType_id = getObjectType(data[i].type);
				}
				tags[item.rmnMediaId] = tag_set;
			}
		}
		
		return tags;
	};
	
	start_index = start_index || initialPointsLoaded;
	dataFlags.loading_points = true;
	setTimeout((function (start_index) {
		return function () {
			var count = initialPointsLoaded;//Math.min(initialPointsLoaded, totalSegmentPoints - start_index);
			if (segmentData) { 
				var segment_id = segmentData.id;
				if (window.memoryCreationWizard) {
					segment_id = memoryCreationWizard.sid;
				}
				if (segment_id) {
					getSegmentPaginated(segment_id, start_index, count, ["photo","video"], function (points) {
						var i = 0,
							media = [],
							data, processed_points;
						if (points) {
							data = JSON.parse(points);
							points = data.splice(3, data.length);
							media.tags = getMediaTags(points);
							for (i = 0; i < points.length; i++) {
								media[i] = getMediaRepresentation(points[i]);
								points[i] = getPointRepresentation(points[i]);
							}
							
							processed_points = {
								owned: points,
								notOwned: []
							};
							
							//force loading of these points and skip loading the media
							loadRmnPoints(processed_points, false, true, true);
							loadPointsSemaphore++;
							mediaRetrieved(media);
							updateLightboxPhotos();
						}
						
						loadPageSemaphore = false;
						dataFlags.loading_points = false;
					});
				} else {
					dataFlags.loading_points = false;
				}
			} else {
				dataFlags.loading_points = false;
			}
			
			setTimeout(function () {
				updateLoadMoreLink('photos', $('#nightCanvasRow .night_img_wrapper_thumb').filter(':visible').length);
			}, 1000);
		}
	})(start_index),150);
}

loadedPages = [true];
nextPageToLoad = 1;
loadPageSemaphore = false;
function loadPage(page) {
	if (initialPointsLoaded) {
		if (page == null) {
			page = nextPageToLoad;
		}
	
		//no need to reload loaded pages or pages beyond the end
		if (!loadedPages[page] && !loadPageSemaphore && (nextPageToLoad <= totalSegmentPages)) {
			loadPageSemaphore = true;
			loadPaginatedData(page*initialPointsLoaded);
			
			//set the next page to load
			loadedPages[page] = true;
			while (loadedPages[nextPageToLoad]) {
				nextPageToLoad++;
			}
			
			if (nextPageToLoad > totalSegmentPages) {
				try {
					if (loadPaginatedPointsInterval != null) clearInterval(loadPaginatedPointsInterval);
				} catch(err) {}
			}
		}
	}
}

function handleAllPointsLoaded() {
	alert('all points loaded');
}

function loadViewableRmnSegmentDelayed(rmn_segment) {
	var processTags = function (response) {
		var tag_str = '', i, segment_tag, tag_name, segment_tags;
		response = JSON.parse(response);
		if (response['status'] == "ok") {
			segment_tags = response['result'];
			if (segment_tags) {
				for (i=0; i<segment_tags.length; i++) {
					segment_tag = segment_tags[i];
					if (segment_tag['partnerId_id'] != '18') {
						tag_name = segment_tag['name'];
						segmentData.tags[tag_name] = segment_tag['id'];
						if (tag_str) tag_str += ', ';
						tag_str += tag_name;
	
						// show get free cards button for weddings
						// if (tag_name == 'wedding' && !editNight)
							// document.getElementById('claimFreeCardsBtnWrapper').style.display = 'block';
					}
				}
			}
		}
		var nightSummaryTags = document.getElementById('nightSummaryTags');
		if (nightSummaryTags) {
			nightSummaryTags.innerHTML = tag_str;
			document.getElementById('nightSummaryEditTagsField').value = tag_str;
			var tags_wrapper = document.getElementById('nightSummaryTagsWrapper');
			if (tag_str) tags_wrapper.style.display = 'block';
			else tags_wrapper.style.display = '';
		}
	};
	
	var segment_title = urldecode(rmn_segment['title']);
	var segment_desc = urldecode(rmn_segment['description']);
	var segment_location_id = rmn_segment['location_id'];
	var segment_tzoffset = rmn_segment['timezoneOffset'];
	var segment_media_id = rmn_segment['media_id'];
	var segment_last_modified = rmn_segment['utcLastModifiedSec'];
	var segment_app_id = rmn_segment['app_id'];
	
	// show get free cards button for weddings
	if (in_array(segment_app_id, [10,11])) {
		//if (!editNight) document.getElementById('claimFreeCardsBtnWrapper').style.display = 'block';
		segmentFlags.weddingAlbum = 1;
	}
	
	// store segment data in memory
	segmentData['title'] = segment_title;
	segmentData['desc'] = segment_desc;
	segmentData['location'] = {};
	if (segment_location_id) {
		segmentData['location']['id'] = segment_location_id;
	}
	segmentData['tzoffset'] = segment_tzoffset;
	segmentData['cover'] = {};
	segmentData['modified'] = segment_last_modified;
	segmentData['app_id'] = segment_app_id;
	if (segment_media_id) {
		segmentData['cover']['id'] = segment_media_id;
	}
	// setSegmentTense();
	
	// create location if location id if null and update segment data
	if (!segment_location_id) {
		createLocation(userProfileObj.id, '', function(data) {
			var location_id = extractJSONid(data);
			if (location_id) {
				segmentData['location']['id'] = location_id;
				editSegment(segmentData.id,{'location_id':location_id}); 
			}
		});
	}
	
	// update date displays
	updateDateDisplays();
	
	// enforce contribute privacy settings
	showContributeElements(); // if (!wizardMemoryData)
	
	if (editNight) { // show invited night messaging
		if (getFid && !segmentFlags.segmentLoadedById) {
			updateInvitedText(getFid);
		} else {
			if (!segmentData.fbOwner) {
				getFacebookUserIdByRmnId(segmentData.owner, function(data) {
					var result = JSON.parse(data);
					var owner_fbid = result['result'];
					if (owner_fbid) {
						updateInvitedText(owner_fbid);
					}
				});
			} else {
				updateInvitedText(segmentData.fbOwner);
			}
		}
	} else {
		updateInvitedText(loggedInUser);
	}
	
	// show segment points if they were already loaded via php
	var nightCanvasItems = document.getElementById('nightCanvasRow').childNodes;
	var i = 0;
	for (i=0; i<nightCanvasItems.length; i++) {
		nightCanvasItems[i].style.display = (dataFlags.edit_mode ? 'inline-block' : 'none');
		/*$(document).ready(function() {
			var nightCanvasItemId = nightCanvasItems[i].id;
			nightCanvasItemId = nightCanvasItemId.replace('_wrapper','');
			var nightCanvasItemSrc = document.getElementById(nightCanvasItemId);
			if (nightCanvasItemSrc && !nightCanvasItemSrc.src)
				nightCanvasItemSrc.src = nightCanvasItemSrc.getAttribute('preload_src');
		});*/
	}
	$(window).trigger('scroll');
	var nightMusicItems = document.getElementById('videoThumbRow');
	if (nightMusicItems) {
		nightMusicItems = nightMusicItems.childNodes;
		for (i=0; i<nightMusicItems.length; i++) {
			nightMusicItems[i].style.display = '';
		}
	}
	
	var nightPostItems = document.getElementById('retroDiaryEntries');
	if (!nightPostItems) nightPostItems = document.getElementById('statusesTabContents');
	if (nightPostItems) {
		nightPostItems = nightPostItems.childNodes;
		for (i=0; i<nightPostItems.length; i++) {
			try {nightPostItems[i].style.display = '';} catch(err){}
		}
	}
	
	try {
		updateLightboxPhotos();
		updateLightboxVideos();
		updateAutoShowRemove('night_img_wrapper_big');
		updateAutoShowRemove('video_thumb_wrapper');
		updateCustomScrollbars();
		updateDiaryExpand();
		clearLoadingAnimations();
	} catch(err) {}
	
	if (display_photo_on_load) setTimeout("displayPhotoByRmnId(display_photo_on_load)", 500);
	
	// load 'contributed by' data
	if (facebook_ids_loaded) {
		for (var i=0; i<facebook_ids_loaded.length; i++) {
			loadFacebookName(facebook_ids_loaded[i]);
		}
	}
	
	if (rmn_ids_loaded) {
		for (var i=0; i<rmn_ids_loaded.length; i++) {
			loadFacebookNameFromRmnId(rmn_ids_loaded[i]);
		}
	}
	
	loadSegmentMusic();
	
	// show night owner in attendee list by default
	if (!segmentData.fbOwner) {
		readFromDB('getFacebookUserIdByRmnId', [segmentData.owner], function(data) {
			var result = JSON.parse(data);
			var owner_fbid = result['result'];
			if (owner_fbid) {
				segmentData.fbOwner = owner_fbid;
				if (owner_fbid == loggedInUser) addToAttendList(owner_fbid, 0, userProfileObj.first_name, userProfileObj.last_name);
				else addToAttendList(owner_fbid);
			}loadSegmentFriends();
		});
	} else {
		addToAttendList(segmentData.fbOwner, 0, userProfileObj.first_name, userProfileObj.last_name);
		loadSegmentFriends();
	}
	
	// load segment tags
	segmentData.tags = {};
	//process tags declared at beginning of function
	getTagsByObject({'objectType':'segment', 'objectIdValue':segmentData.id}, processTags);
	
	// load segment thumb
	if (segment_media_id) {
		getMedia(segment_media_id, function (data) {
			var response = JSON.parse(data);
			if (response["status"] == "ok") {
				var result = response["result"];
				if (result && result.length) {
					var segment_cover = result[0];
					var segment_cover_src = urldecode(segment_cover['src']);
					var segment_cover_thumb = urldecode(segment_cover['thumb']);
					// show semgent thumb (or remove it if media no longer exists)
					refreshSegmentThumb(segment_cover_src, segment_cover_thumb);
				}
			}
		});//readFromDB('getLocations', [segment_location_id], loadLocationInfo);
	} else if (wizardMemoryThumb) {
		segment_media_id = wizardMemoryThumb[0];
		segmentData.cover.id = segment_media_id;
		var segment_cover_src = wizardMemoryThumb[1];
		var segment_cover_thumb = wizardMemoryThumb[2];
		// show semgent thumb
		refreshSegmentThumb(segment_cover_src, segment_cover_thumb);
	}
	
	// load segment location
	if (segment_location_id) {
		getLocations(segment_location_id, loadLocationInfo);
	} else {
		updateNightInfo();
	}
	
	// load points from segment	
	loadRmnPointsFromDB(segmentData.owner, segmentData.start, segmentData.end);
	
	// load fb stream data if coming from wizard
	/*if (wizardMemoryData) {
		reloadFacebookStream();
	}*/
		
	// process post auth action (if applicable)
	var postAuthAction = $.cookies.get("postAuthAction");
	if (postAuthAction) { // note: attend is handled separately
		if (postAuthAction == 'photos') {
			loadUserAlbums();initColorbox('', 'addPhotosWrapper');
		} else if (postAuthAction == 'videos') {
			loadUserVideos();initColorbox('', 'addVideosWrapper');
		} else if (postAuthAction == 'music') {
			initColorbox('', 'addMusicWrapper');
		} else if (postAuthAction == 'friends') {
			loadUserFriends();initColorbox('', 'addFriendsWrapper');
		} else if (postAuthAction == 'posts') {
			editDiaryEntry('new');
		}
		
		if (postAuthAction != 'attend') {
			$.cookies.set("postAuthAction", null);
		}
	}
	
	// show timeline bars
	// renderTimelineBars();
	
	// update contribute after wizard bulk save completes
	if (wizardMemoryData) {
		segmentFlags.wizardShowContributeReady = 1;
		if (segmentFlags.wizardShowContributeCalled) saveCompleteShowContribute();
	}
	
	if (initialPointsLoaded != totalSegmentPoints) {
		if (true || $.browser.msie) loadPaginatedPointsInterval = null;
		else loadPaginatedPointsInterval = setInterval(loadPage, 1500);
	} else loadPaginatedPointsInterval = null;
	
	if (segmentFlags.cached) {
		if (typeof checkTriggerPaginate == 'function') {
			$(window).scroll(checkTriggerPaginate);
			$(window).resize(checkTriggerPaginate);
		}
		
		if ($("#nightCanvas").data('jsp')) {
			$("body").bind('mouseup', function () {
				var nc = $("#nightCanvas"),
					api = nc.data('jsp'),
					cp = api.getContentPane(),
					ncr = $("#nightCanvasRow"),
					scroll_percent;
					
				if (dataFlags.gridView) scroll_percent = (cp.position().top * -1) / (cp.height() - nc.height());
				else scroll_percent = ((cp.position().left * -1) / (ncr.width() - cp.width()));
				if (scroll_percent > 0.70) loadPage();
			});
		} // */

		/* $("#nightCanvas").bind('jsp-scroll-x', function (event, scrollPosition, isAtLeft, isAtRight) {
			var api = $(this).data('jsp'),
				cp = api.getContentPane(),
				ncr = $("#nightCanvasRow"),
				max_left = ncr.width() - cp.width(),
				scroll_percent = (scrollPosition / max_left);

			if (isAtRight || (scroll_percent > 0.80)) {
				loadPage();
			}
		}) // */
		$("#nightCanvas").bind('jsp-scroll-y', function (event, scrollPosition, isAtBottom, isAtTop) {
			var api = $(this).data('jsp'),
				cp = api.getContentPane(),
				nc = $("#nightCanvas"),
				scroll_percent = (cp.position().top * -1) / (cp.height() - nc.height());
				
			if (scroll_percent > 0.75) {
				loadPage();
			}
		}); // */
	}
}


function loadSegmentFriends() {
	// load segment friends
	if (!dataFlags.segmentFriendsLoaded) {
		dataFlags.segmentFriendsLoaded = 1;
		var hide_empty;
		if (!wizardMemoryFriends) {
			readFromDB('getUsersBySegment', [segmentData.id], function(response) {
				response = JSON.parse(response);
				if (response['status'] == "ok") {
					var segment_friends = response['result'];
					var num_friends = segment_friends.length;
					var show_attend_btn = 1;
					for (var i=0; i<num_friends; i++) {
						var segment_friend = segment_friends[i];
						var rmnid = segment_friend['user_id'];
						var fbid = segment_friend['serviceUserId'];
						var user_firstname = segment_friend['firstName'];
						var user_lastname = segment_friend['lastName'];
						if (user_firstname == 'not_set') user_firstname = '';
						if (user_lastname == 'not_set') user_lastname = '';
						if (fbid == loggedInUser) show_attend_btn = 0;
						segmentFriendIds.push(rmnid); // add rmn id to array for pairing
						segmentFriendFbIds[fbid] = 1; // keep track of what to highlight in friends widget
						var friend_wrapper = document.getElementById('f'+fbid);
						if (friend_wrapper) friend_wrapper.className = 'friend_wrapper_selected';
						addToAttendList(fbid, 0, user_firstname, user_lastname);
					}
					
					// enforce contribute privacy to attend button
					var contribute_privacy = segmentData && segmentData.privacy && segmentData.privacy.contribute;
					if (contribute_privacy != 'cpr' && editNight) {
						if (contribute_privacy == 'cli') showAttendBtn(show_attend_btn);
						else if (contribute_privacy == 'cfr') {
							if (!dataFlags.offlineView) {
								if (segmentFlags.segmentLoadedById) {
									readFromDB('getFacebookUserIdByRmnId', [segmentData.owner], function(data) {
										var result = JSON.parse(data);
										var owner_fbid = result['result'];
										if (owner_fbid) checkFbFriendsForAttendBtn(owner_fbid, show_attend_btn);
									});
								} else checkFbFriendsForAttendBtn(getFid, show_attend_btn);
							} else showAttendBtn(show_attend_btn);
						}
					}updateFriendCount();
					
					// auto refresh fb data
					if (segmentFlags.cached) refresh_facebook_data();
					if (num_friends) hide_empty = 1;
				}
				
				if (editNight) {
					hide_empty = 1;
				}
				
				// update no friends messaging
				updateTabStatus('friends', hide_empty);
			}); 
		} else {
			for (var i=0; i<wizardMemoryFriends.length; i++) addToAttendList(wizardMemoryFriends[i][0], 0, wizardMemoryFriends[i][1], wizardMemoryFriends[i][2]);
			if (wizardMemoryFriends.length) hide_empty = 1;
			// update no friends messaging
			updateTabStatus('friends', hide_empty);
		}
	}
}

function checkFbFriendsForAttendBtn(owner_fbid, show_attend_btn) {
	if (segmentFlags.viewerIsFriend == null) {
		var isFriendsFQL = buildIsFriendFQL(owner_fbid);
		queryFacebook(isFriendsFQL.fql, isFriendsFQL.args, function(data) {
			if (data && data.length) {
				segmentFlags.viewerIsFriend = 1;
				showAttendBtn(show_attend_btn);
			} else segmentFlags.viewerIsFriend = 0;
		});
	} else if (segmentFlags.viewerIsFriend) showAttendBtn(show_attend_btn);
}

function loadUserPointsFromDb (rmnid, start_time, end_time) {
	readFromDB('getPointsByUser', [[rmnid.toString()], start_time, end_time], function(response) {
		var i = 0;
		response = JSON.parse(response);
		if (response['status'] == "ok") {
			var rmn_points = response['result'],
				filtered_points = {owned:[],notOwned:[]};
			if (rmn_points && rmn_points.notOwned) {
				for (i = 0; i < rmn_points.notOwned.length ; i++) {
					if (rmn_points.notOwned[i].app_id != 8) {
						filtered_points.notOwned.push(rmn_points.notOwned[i]);
					}
				}
			}

			if (rmn_points && rmn_points.owned) {
				for (i = 0; i < rmn_points.owned.length ; i++) {
					// if the point is not a kapturcards point
					if (rmn_points.owned[i].app_id != 8) {
						filtered_points.owned.push(rmn_points.owned[i]);
					}
				}
			}
			
			handleRmnPointsLoadedFromDb(filtered_points);
		}
	});
}

function handleRmnPointsLoadedFromDb (points) {
	var photosTab = document.getElementById('photosTab'),
		statusesTab = document.getElementById('statusesTab');
	
	if (photosTab && photosTab.style.display != 'block' && statusesTab && statusesTab.style.display != 'block') {
		clientLoadDelayed = function(callback) {
			loadRmnPoints(points, null, !dataFlags.edit_mode);
			displayMoreStreamItems();
			safeCall(callback, []);
		};
	} else {
		loadRmnPoints(points, null, !dataFlags.edit_mode);
		if (!dataFlags.edit_mode) {
			displayMoreStreamItems();
		}
	}
}

function loadRmnPointsFromDB(rmnid, start_time, end_time) {
	var memoryCreationWizard = window.memoryCreationWizard,
		segmentData = window.segmentData,
		kapturDb = window.kapturDb,
		segment_id;
	updateShareLinks(); // update share links
	// segmentData.numPostsLoaded = 0;
	
	//get the segment id
	segment_id = memoryCreationWizard.sid || segmentData.id;
	
	if (has_segment_point_table && kapturDb && segment_id) {
		//loads the points in based on segment point tables
		kapturDb.getPointsInSegmentWithInfo(segment_id, function (segment_point_table) {
			var points = {
				owned : segment_point_table || [],
				notOwned : []
			};
			
			handleRmnPointsLoadedFromDb(points);
		});
	} else {
		//loads the points with the old method
		loadUserPointsFromDb (rmnid, start_time, end_time);
	}
	
	
	
	// set still saving unload handler
	if (!dataFlags.offlineView) window.onbeforeunload = setStillSavingExitHandler;
}

/**
 * Sorts parallell arrays of points and times
 * 
 * returns an object with sorted versions of the passed in arrays
 */
function sortPointsByTimes(points, times) {
	var sort_function = function (a, b) {
			//negative when a.time < b.time, zero when a.time == b.time, positive when a.time > b.time
			return a.time - b.time;
		},
		points_with_times = [],
		i, num_points, point_time;
	
	num_points = arrayLength(points);
	for (i = 0; i < num_points; i++) {
		points_with_times.push({
			point_id : points[i],
			time : times[i]
		});
	}
	
	points_with_times.sort(sort_function);
	
	points = [];
	times = [];
	for (i = 0; i < num_points; i++) {
		point_time = points_with_times[i];
		points.push(point_time['point_id']);
		times.push(point_time['time']);
	}
	
	points_with_times = {
		points : points,
		times : times
	};
	
	return points_with_times
}

function addPointsToSegmentPointTable(segment_id, new_point_ids, new_point_times, callback) {
	var sorted_points_with_times;
	
	//if don't user segment point tables if the segment has points and not a segment point table
	// this is for compatability with older segments
	if (!has_segment_point_table && count(rmnPoints)) {
		return;
	}
	
	//sort the new points by time
	sorted_points_with_times = sortPointsByTimes(new_point_ids, new_point_times);
	new_point_ids = sorted_points_with_times['points'];
	new_point_times = sorted_points_with_times['times'];
	
	//add the points to the end of the segment
	//kapturDb.addPointsToSegment(segment_id, new_point_ids, null, function () {
		var segment_point_table = kapturDb.models.getSegmentPointTable(segment_id),
			new_point_positions = [],
			new_points_index, num_new_points, old_points_index, num_old_points,
			old_point_id, old_point, new_point_time, old_point_time;

		num_new_points = arrayLength(new_point_ids);
		num_old_points = arrayLength(segment_point_table) - num_new_points;
		new_points_index = 0;
		old_points_index = 0;
		//determine the new point positions
		while ((new_points_index < num_new_points) && (old_points_index < num_old_points)) {
			old_point_id = segment_point_table[old_points_index];
			old_point = rmnPoints[old_point_id];
			if (!old_point) {
				//handle case when old point does not actually exist (by ignoring it)
				num_old_points--;
				old_points_index++;
				continue;
			}
			new_point_time = new_point_times[new_points_index];
			old_point_time = parseInt(old_point['utcTimeSec'], 10);
			
			if (new_point_time < old_point_time) {
				new_point_positions.push(num_old_points + new_points_index + 1);
				new_points_index++;
			} else {
				new_point_positions.push(old_points_index + 1);
				old_points_index++;
			}
		}
		
		while (new_points_index < num_new_points) {
			new_point_positions.push(num_old_points + new_points_index + 1);
			new_points_index++;
		}
		
		while (old_points_index < num_old_points) {
			new_point_positions.push(old_points_index + 1);
			old_points_index++;
		}
		
		//change the positions of the points
		//kapturDb.changePointPositionsInSegment(segment_id, new_point_positions, callback);
	//});
}

function addPointToSegmentPointTable(segment_id, new_point_id, new_point_time, callback) {
	var segment_point_table = kapturDb.models.getSegmentPointTable(segment_id),
		segment_point_table_length = arrayLength(segment_point_table),
		position = segment_point_table_length,
		i, time, point, point_id;
	
	//if don't user segment point tables if the segment has points and not a segment point table
	// this is for compatability with older segments
	if (!has_segment_point_table && count(rmnPoints)) {
		return;
	}
	
	for (i = 0; i < segment_point_table_length; i++) {
		point_id = segment_point_table[i];
		point = rmnPoints[point_id];
		if (point) {
			time = point['utcTimeSec'];
			if (new_point_time < time) {
				position = i;
				break;
			}
		}
	}
	
	//the positioning is 1 based so it must be adjusted
	position = position + 1;
	
	kapturDb.addPointToSegment(segment_id, new_point_id, position + 1, callback);
}

function addMediaToNight(media_id, point_args, media_args, media_tags) {
	if (!segmentFlags.dupCount) segmentFlags.dupCount = 0;

	// update segment cover image if it's not already updated
	try {
		try { // for flickr and uploaded photos on p=nw
			if (!memoryCreationWizard.weddingCover && !editNight) {
				var is_flickr;
				if (point_args['service'] == SERVICE_TYPES.flickr) is_flickr = 1;
				//setWeddingCover(media_id, is_flickr);
			}
		} catch(err) {
			if (media_args['mediaType_id'] == MEDIA_TYPES.photo && !segmentData.cover.thumb) {
				var cover_src = urldecode(urldecode(media_args['src']));
				var cover_thumb = urldecode(urldecode(media_args['thumb']));
				refreshSegmentThumb(cover_src, cover_thumb);
			}
		}
	} catch(err) {}
	
	point_args['dup'] = segmentFlags.dupCount++;
	
	if (rmnAppId) {
		point_args['app_id'] = rmnAppId;
	}
	
	var point_owner = loggedInUser;
	
	if (userProfileObj.pairNewPoints && segmentData.fbOwner) {
		point_owner = segmentData.fbOwner;
	}
	
	writeToDB('createPoint', [point_args, point_owner], (function(media_id, media_args, point_owner) {
		return function(data) {
			// construct proper partner type id
			var media_type_id = media_id;
			var partner_type = media_args['partnerId_id'];
			if ((partner_type == PARTNER_TYPES.youtube_video) || (partner_type == PARTNER_TYPES.youtube_music)) {
				media_type_id += 'yt';
			} else if ((partner_type == PARTNER_TYPES.vimeo_video) || (partner_type == PARTNER_TYPES.vimeo_music)) {
				media_type_id += 'vim';
			} else if (partner_type == PARTNER_TYPES.flickr_photo) {
				media_type_id += 'flickr';
			}

			// special handling for music
			if ((partner_type == PARTNER_TYPES.youtube_music) || (partner_type == PARTNER_TYPES.vimeo_music)) {
				media_type_id += 'music';
			}
			
			// update values in memory
			var point_id = extractJSONid(data);
			
			addPointToSegmentPointTable(segmentData.id, point_id, point_args['utcTimeSec']);
			
			point_args['description'] = urldecode(urldecode(point_args['description']));
			point_args['partnerIdValue'] = urldecode(urldecode(point_args['partnerIdValue']));
			rmnPoints[point_id] = point_args;
			rmnPoints[point_id]['id'] = point_id;
			rmnPoints[point_id]['user_id'] = userProfileObj.id;
			rmnPoints[point_id]['media_type_id'] = media_id;
			rmnPoints[point_id]['tags'] = media_tags;
			rmnPoints[point_id]['width'] = media_args['width'];
			rmnPoints[point_id]['height'] = media_args['height'];
			rmnPoints[point_id]['source'] = urldecode(urldecode(media_args['src']));
			rmnPoints[point_id]['media_src'] = rmnPoints[point_id]['source'];
			rmnPoints[point_id]['thumbnail'] = urldecode(urldecode(media_args['thumb']));
			rmnPoints[point_id]['media_thumb'] = rmnPoints[point_id]['thumbnail'];

			loadFacebookNameFromRmnId(rmnPoints[point_id]['user_id'], point_id);
			if (partner_type == PARTNER_TYPES.flickr_photo) {
				//loadFlickrName(rmnPoints[point_id]['partnerIdValue']);
			} else loadFacebookName(rmnPoints[point_id]['partnerIdValue']);
			
			var remove_params; // holds point delete params for items removed before point id is generated
			var media_temp_point_id = 'm'+media_type_id+'_wrapper'; // derive temp point id
			var media_temp_point_data = rmnPoints[media_temp_point_id];
			if (media_temp_point_data) remove_params = media_temp_point_data['removed'];
			var media_wrapper = document.getElementById(media_temp_point_id);
			if (media_wrapper) {
				media_wrapper.setAttribute('point_id', point_id); // swap in actual point id
				if (rmnPoints[media_temp_point_id]) {
					if (rmnPoints[media_temp_point_id]['point_id']) {
						delete rmnPoints[point_id]; // remove point data if temp point data doesn't exist
					}
					delete rmnPoints[media_temp_point_id]; // remove the temp data
				}
			} else {
				if (!rmnPoints[media_temp_point_id]) rmnPoints[media_temp_point_id] = {};
				rmnPoints[media_temp_point_id]['point_id'] = point_id; // store generated point id if point is created before media is loaded into canvas
			}
			
			// store point id for removal
			var media_type = media_args['mediaType_id'];
			if (partner_type == PARTNER_TYPES.flickr_photo) {
				//Temporary until we properly add points to slideshow on the fly
				//SlideShow.show_reload = true;
				pointIdArray = flickrPhotoPointIds;
			} else if (media_type == MEDIA_TYPES.video || media_type == MEDIA_TYPES.music) {
				pointIdArray = fbVideoPointIds;
			} else {
				//Temporary until we properly add points to slideshow on the fly
				//SlideShow.show_reload = true;
				pointIdArray = fbPhotoPointIds;
			}
			pointIdArray[media_type_id] = point_id;
			
			// call remove function if media is already removed in the ui
			if (remove_params) {
				removeCanvasItem(remove_params[0], remove_params[1]);
			} else {
				// create media
				writeToDB('createMedia', [media_args, point_owner], (function(point_id, media_type_id) {
					return function(data) {
						var media_id = extractJSONid(data);
						var media_type = media_args['mediaType_id'];
						var media_src = urldecode(urldecode(media_args['src']));
						var media_thumb = urldecode(urldecode(media_args['thumb']));
						writeToDB('pairMediaAndPoint', [[media_id], point_id]);
						
						// create media people tags
						for (var i in media_tags) createMediaUserTag(media_id, {'uid':i}, rmnPoints[point_id]); // media_tags[i]
						
						// set segment cover if it's not already set
						if (media_type == MEDIA_TYPES.photo && (segmentData.cover&&!segmentData.cover.id&&segmentData.cover.thumb == media_thumb)) {
							try {
								if (media_id == memoryCreationWizard.weddingCover&&0)
									setWeddingCover(media_id);
							} catch(err) {
								if (segmentData.id) writeToDB('editSegment', [{'media_id':media_id}, segmentData.id]);
								segmentData.cover.id = media_id; // update point media data
							}
							updatePointMediaData(point_id, media_id, media_src, media_thumb);
						}
						
						// store media id (for tagging)
						if (!rmnPoints[point_id]) rmnPoints[point_id] = {};
						rmnPoints[point_id]['media_id'] = media_id;
						
						// set segment cover if it's not already set
						try {
							if (!memoryCreationWizard.weddingCover)
								setWeddingCover(media_args['partnerIdValue'], 0, point_id);
						} catch(err) {}
						
						// flag slideshow reload
						if (window.weddingCoverSlideshow) weddingCoverSlideshow.flagReload();
					}
				}) (point_id, media_type_id));
				
				// pair point to segment owner or friends depending on whether user is segment owner
				if (media_type != MEDIA_TYPES.music) pairUsersToPoint(point_id);
				
				// update select cover from kaptur thumbs
				if (partner_type == PARTNER_TYPES.flickr_photo) {
					try {addRemoveFromKapturCoverSelect(point_id);} catch(err) {}
				}
			}
		}
	}) (media_id, media_args, point_owner));
}

function createMediaUserTag(media_id, tag_data, point_data, partner_media_id) {
	writeToDB('createTag', [{
		'objectType':'media',
		'objectIdValue':media_id,
		'name':tag_data['uid'],
		'partnerId_id':'15',
		'partnerIdValue':d_escape(JSON.stringify(tag_data))}],
		function(data) {
			if (point_data && !point_data['tags']) {
				point_data['tags'] = {};
			}
			point_data['tags'][tag_data['uid']] = extractJSONid(data);
		}); // '{"uid":"'+uid+'"}'
	
	// persist tag to facebook
	var saveFBTags = document.getElementById('saveFBTags');
	if (saveFBTags && saveFBTags.checked) {
		FB.api({
			method: 'photos.addTag', pid:partner_media_id,
			tags:[{tag_uid:tag_data['uid'], x:50, y:50}]
		}, function(response) {});
	}
}

function pairUsersToPoint(point_id) {
	segmentPairingIds.push(point_id); // store point id for friend pairing	
	if (editNight && !userProfileObj.pairNewPoints) writeToDB('pairUsersAndPoint', [[segmentData.owner], point_id, 'suggested']);
	else if (segmentFriendIds.length || userProfileObj.pairNewPoints) {
		if (segmentFriendIds && segmentFriendIds.length < 110)
			writeToDB('pairUsersAndPoint', [segmentFriendIds.slice(0,110), point_id, 'suggested']);
	}
}

function mediaCreated(data, pointId, pointTime) {
	var mediaId = extractJSONid(data);
	
	// update div media id attribute
	var pointDiv = document.getElementById(pointTime+"_"+pointId);
	if (pointDiv) pointDiv.setAttribute('rmnMediaId', mediaId);
	
	arrayAsJSON = [[mediaId], pointId];
	writeToDB('pairMediaAndPoint', arrayAsJSON);
}

function buildPoint(point_args, stream_args) {
	if (!segmentFlags.dupCount) segmentFlags.dupCount = 0;
	point_args['dup'] = segmentFlags.dupCount++;
	if (rmnAppId) point_args['app_id'] = rmnAppId;
	var point_owner = loggedInUser;
	if (userProfileObj.pairNewPoints && segmentData.fbOwner) {
		point_owner = segmentData.fbOwner;
		// % is used for detecting json
		//if (point_args['partnerIdValue'].indexOf('%') == -1) point_args['partnerIdValue'] = point_owner;
		//stream_args['actorId'] = point_owner;
	}
	
	writeToDB('createPoint', [point_args, point_owner], (function (point_args, stream_args) {
		return function(data) {
			var point_id = extractJSONid(data);
			var partner_id = point_args['partnerId_id'];
			var createTime = stream_args['createTime'];
			
			addPointToSegmentPointTable(segmentData.id, point_id);
			
			// update values in memory
			point_args['description'] = urldecode(urldecode(point_args['description']));
			point_args['partnerIdValue'] = urldecode(point_args['partnerIdValue']);
			rmnPoints[point_id] = point_args;
			rmnPoints[point_id]['id'] = point_id;
			rmnPoints[point_id]['user_id'] = userProfileObj.id;
			
			// pair users to point (for partner_id 6)
			if ((editNight && !userProfileObj.pairNewPoints) || !in_array(partner_id, [PARTNER_TYPES.facebook_post, PARTNER_TYPES.rmn_guest_list, PARTNER_TYPES.facebook_link, PARTNER_TYPES.youtube_music, PARTNER_TYPES.vimeo_music])) pairUsersToPoint(point_id);
			
			// insert diary entry
			toggleSection('retroDiaryEntries', 1); // make sure diary entry is expanded
			insertDiaryEntry(stream_args, createTime, point_id, diaryIsCollapsed());
		}
	}) (point_args, stream_args));
}



function deleteSegment(sid, activator) {
	if (confirm("Are you sure you want to delete this memory?")) {
		//kapturDb.removeAllPointsFromSegment(sid);
		writeToDB('deleteSegment', [sid]);
		if (activator) {
			/*var activator_elem = activator.parentNode;
			var activator_wrapper = activator_elem.parentNode;
			activator_wrapper.removeChild(activator_elem);*/
			var activator_wrapper = $(activator).closest('.thumb_stack_wrapper');
			activator_wrapper.remove();
			var profilePageNightCount = document.getElementById('profilePageNightCount');
			if (profilePageNightCount) {
				profileData.segments.count--;
				var segment_count = profileData.segments.count;
				profilePageNightCount.innerHTML = segment_count+' night'+(segment_count!=1?'s':'');
			}
		}
	}
}

function updateSegmentTags() {
	var tags_field = document.getElementById('nightSummaryEditTagsField');
	var tags_text = document.getElementById('nightSummaryTagsWrapper');
	if (!segmentData.tags) segmentData.tags = {}; // initialize tags obj if it's not defined
	var formatted_tag_str = formatTagStr(tags_field.value);
	document.getElementById('nightSummaryTags').innerHTML = formatted_tag_str;
	var tag_values = formatted_tag_str.split(', ');
	var segment_tags = segmentData.tags;
	tags_field.value = formatted_tag_str;
	if (!formatted_tag_str) tags_text.style.display = '';
	else tags_text.style.display = 'block';
	
	// delete removed tags
	for (var i in segment_tags) {
		if (!in_array(i, tag_values)) {
			if (!dataFlags.offlineView) {
				var segment_tag = segment_tags[i];
				writeToDB('deleteTag', [segment_tag]);
			}delete segment_tags[i];
		}
	}
	
	// add new tags
	for (var i=0; i<tag_values.length; i++) {
		var tag_value = tag_values[i];
		if (tag_value && !segment_tags[tag_value]) {
			if (!dataFlags.offlineView) {
				writeToDB('createTag', [{'objectType':'segment', 'objectIdValue':segmentData.id, 'name':tag_value}],
					(function (tag_value) {
						return function(data) {
							segment_tags[tag_value] = extractJSONid(data); // store tag id
						}
					}) (tag_value));
			} else segment_tags[tag_value] = 1;
		}
	}
}

