private ENSessionUploadContext UploadNote_DetermineDestination(ENSessionUploadContext context)
		{
			// Begin prepping a resulting note ref.
			context.NoteRef = new ENNoteRef();

			// If this app uses an app notebook and that notebook is linked, then no matter what the caller says,
			// we're going to need to use the explicit notebook destination to comply with shared notebook auth.
			if (AppNotebookIsLinked)
			{
				// Do we have a cached linked notebook record to use as a destination?
				LinkedNotebook linkedNotebook = (LinkedNotebook)Preferences.ObjectForKey(ENSessionPreferencesLinkedAppNotebook);
				if (linkedNotebook != null)
				{
					context.NoteStore = NoteStoreForLinkedNotebook(linkedNotebook);
					context.NoteRef.Type = ENNoteRef.ENNoteRefType.TypeShared;
					context.NoteRef.LinkedNotebook = ENLinkedNotebookRef.LinkedNotebookRefFromLinkedNotebook(linkedNotebook);

					// Because we are using a linked app notebook, and authenticating to it with the shared auth model,
					// we must provide a notebook guid in the note or face an error.
					SharedNotebook sharedNotebook = (SharedNotebook)Preferences.ObjectForKey(ENSessionPreferencesSharedAppNotebook);
					context.Note.NotebookGuid = sharedNotebook.NotebookGuid;
				}
				else
				{
					// We don't have a linked notebook record to use.  We need to go find one.
					context = UploadNote_FindLinkedAppNotebook(context);
					return context;
				}
			}

			if (context.NoteStore == null)
			{
				if (context.RefToReplace != null)
				{
					context.NoteStore = NoteStoreForNoteRef(context.RefToReplace);
					context.NoteRef.Type = context.RefToReplace.Type;
					context.NoteRef.LinkedNotebook = context.RefToReplace.LinkedNotebook;
				}
				else if (context.Notebook != null && context.Notebook.IsBusinessNotebook)
				{
					context.NoteStore = BusinessNoteStore;
					context.NoteRef.Type = ENNoteRef.ENNoteRefType.TypeBusiness;
				}
				else if (context.Notebook != null && context.Notebook.IsLinked)
				{
					context.NoteStore = NoteStoreForLinkedNotebook(context.Notebook.LinkedNotebook);
					context.NoteRef.Type = ENNoteRef.ENNoteRefType.TypeShared;
					context.NoteRef.LinkedNotebook = ENLinkedNotebookRef.LinkedNotebookRefFromLinkedNotebook(context.Notebook.LinkedNotebook);
				}
				else
				{
					// This is the normal case. Either the app has not specified a destination notebook, or the
					// notebook is personal.
					context.NoteStore = PrimaryNoteStore;
					context.NoteRef.Type = ENNoteRef.ENNoteRefType.TypePersonal;
				}
			}

			if (context.RefToReplace != null)
			{
				context = UploadNote_Update(context);
			}
			else
			{
				context = UploadNote_Create(context);
			}

			return context;
		}
		public ENNoteRef UploadNote(ENNote note, ENSession.UploadPolicy policy, ENNotebook notebook, ENNoteRef noteToReplace)
		{

			if (note == null)
			{
				ENSDKLogger.ENSDKLogError("Must specify note");
				throw new ENInvalidDataException();
			}

			if (policy == UploadPolicy.Replace && noteToReplace == null || policy == UploadPolicy.ReplaceOrCreate && noteToReplace == null)
			{
				ENSDKLogger.ENSDKLogError("Must specify existing ID when requesting a replacement policy");
				throw new ENInvalidDataException();
			}

			if (policy == UploadPolicy.Create && noteToReplace != null)
			{
				ENSDKLogger.ENSDKLogError("Can't use create policy when specifying an existing note ref. Ignoring.");
				noteToReplace = null;
			}

			if (notebook != null && !notebook.AllowsWriting)
			{
				var errorMessage = "A specified notebook must not be readonly";
				ENSDKLogger.ENSDKLogError(errorMessage);
				throw new ArgumentException(errorMessage);
			}

			if (!IsAuthenticated)
			{
				throw new ENAuthExpiredException();
			}

			// Run size validation on any resources included with the note. This is done at upload time because
			// the sizes are a function of the user's service level, which can change.
			if (!note.ValidateForLimits())
			{
				ENSDKLogger.ENSDKLogError("Note failed limits validation. Cannot upload.");
				throw new ENLimitReachedException();
			}

			ENSessionUploadContext context = new ENSessionUploadContext();
			if (noteToReplace != null)
			{
				context.Note = note.EDAMNoteToReplaceServiceNoteGUID(noteToReplace.Guid);
			}
			else
			{
				context.Note = note.EDAMNote();
			}
			context.RefToReplace = noteToReplace;
			context.Notebook = notebook;
			context.Policy = policy;

			context = UploadNote_DetermineDestination(context);
			return context.NoteRef;
		}
		private ENSessionUploadContext UploadNote_Create(ENSessionUploadContext context)
		{
			// Clear create and update dates. The service will set these to sensible defaults for a new note.
			context.Note.Created = 0;
			context.Note.Updated = 0;

			// Write in the notebook guid if we're providing one.
			if (context.Note.NotebookGuid == null && context.Notebook != null)
			{
				context.Note.NotebookGuid = context.Notebook.Guid;
			}

			try
			{
				Note resultNote = context.NoteStore.CreateNote(context.Note);
				context.NoteRef.Guid = resultNote.Guid;
				//context = UploadNote_Complete(context)
			}
			catch (Exception ex)
			{
				context.NoteRef = null;
				ENSDKLogger.ENSDKLogError(string.Format("Failed to createNote for uploadNote: {0}", ex.Message));
				throw new Evernote.EDAM.Error.EDAMNotFoundException();
			}
			return context;
		}
		private ENSessionUploadContext UploadNote_FindSharedAppNotebook(ENSessionUploadContext context)
		{
			LinkedNotebook linkedNotebook = (LinkedNotebook)Preferences.ObjectForKey(ENSessionPreferencesLinkedAppNotebook);
			ENNoteStoreClient linkedNoteStore = NoteStoreForLinkedNotebook(linkedNotebook);
			try
			{
				SharedNotebook sharedNotebook = linkedNoteStore.GetSharedNotebookByAuth();
				if (sharedNotebook != null)
				{
					// Persist the shared notebook record.
					Preferences.SetObject(sharedNotebook, ENSessionPreferencesSharedAppNotebook);
					// Go back and redetermine the destination.
					context = UploadNote_DetermineDestination(context);
				}
				else
				{
					// Uh-oh; there's no destination to use. We have to fail the request.
					ENSDKLogger.ENSDKLogError("getSharedNotebookByAuth for uploadNote returned empty sharedNotebook; turning into NotFound.");
					throw new Evernote.EDAM.Error.EDAMNotFoundException();
				}
			}
			catch (Exception ex)
			{
				// Uh-oh; there's no destination to use. We have to fail the request.
				ENSDKLogger.ENSDKLogError(string.Format("Failed to getSharedNotebookByAuth for uploadNote; turning into NotFound: {0}", ex.Message));
				throw new Evernote.EDAM.Error.EDAMNotFoundException();
			}
			return context;
		}
		private ENSessionUploadContext UploadNote_FindLinkedAppNotebook(ENSessionUploadContext context)
		{
			try
			{
				// We know the app notebook is linked. List linked notebooks; we expect to find a single result.
				List<LinkedNotebook> linkedNotebooks = PrimaryNoteStore.ListLinkedNotebooks();
				if (linkedNotebooks.Count < 1)
				{
					// Uh-oh; there's no destination to use. We have to fail the request.
					string errorMessage = "Cannot find linked app notebook. Perhaps user deleted it?";
					ENSDKLogger.ENSDKLogError(errorMessage);
					throw new Exception(errorMessage);
				}
				if (linkedNotebooks.Count > 1)
				{
					ENSDKLogger.ENSDKLogInfo(string.Format("Expected to find single linked notebook, found {0}", linkedNotebooks.Count));
				}
				// Take this notebook, and cache it.
				LinkedNotebook linkedNotebook = linkedNotebooks[0];
				if (linkedNotebook.ShareKey == null)
				{
					// The notebook is a public notebook so it's read only. Fail the request with error.
					throw new ENPermissionDeniedException();
				}
				Preferences.SetObject(linkedNotebook, ENSessionPreferencesLinkedAppNotebook);

				// Go find the shared notebook that corresponds to this.
				context = UploadNote_FindSharedAppNotebook(context);
				return context;
			}
			catch (Exception ex)
			{
				// Uh-oh; there's no destination to use. We have to fail the request.
				ENSDKLogger.ENSDKLogError(string.Format("Failed to listLinkedNotebooks for uploadNote; turning into NotFound: {0}", ex.Message));
				throw new Evernote.EDAM.Error.EDAMNotFoundException();
			}

		}
		private ENSessionUploadContext UploadNote_Update(ENSessionUploadContext context)
		{
			// If we're replacing a note, fixup the update date.
			context.Note.Updated = DateTime.Now.ToEdamTimestamp();

			context.Note.Guid = context.RefToReplace.Guid;
			context.Note.Active = true;

			try
			{
				Note resultNote = context.NoteStore.UpdateNote(context.Note);
				context.NoteRef = context.RefToReplace; // The result by definition has the same ref.
				//context = UploadNote_Complete(context)
			}
			catch (Evernote.EDAM.Error.EDAMNotFoundException ex)
			{
				if (ex.Message.Contains("Note.guid"))
				{
					// We tried to replace a note that isn't there anymore. Now we look at the replacement policy.
					if (context.Policy == UploadPolicy.ReplaceOrCreate)
					{
						// Can't update it, just create it anew.
						context.Note.Guid = null;
						context.Policy = UploadPolicy.Create;
						context.RefToReplace = null;

						// Go back to determining the destination before creating. We'll take into account a supplied
						// notebook at this point, which may actually be in a different place than the note we were
						// trying to replace. We don't have enough information otherwise to reliably place a new note
						// in the same notebook as the original one, so defaulting to a default notebook in a given
						// note store is less predictable than defaulting to the default overall. In practice, this
						// works out the same most of the time. (For app notebook apps, it'll end up in the app notebook
						// anyway of course.)
						context = UploadNote_DetermineDestination(context);
						return context;
					}
				}
				ENSDKLogger.ENSDKLogError(string.Format("Failed to updateNote for uploadNote: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			catch (Exception ex)
			{
				ENSDKLogger.ENSDKLogError(string.Format("Failed to updateNote for uploadNote: {0}", ex.Message));
				throw new Exception(ex.Message, ex.InnerException);
			}
			//context = UploadNote_Complete(context)
			return context;
		}