/*
 * This file is generated.  Do not edit it directly.
 * Run 'ant annotate' to regenerate it.  See tools.javascript.JSConstantApf
 */

var LookupInputElement = {
'LOOKUP_IFRAME' : "lookupIFrame",
'pLOOKUP_WIDGET' : "_lkwgt",
'DIALOG_ID' : "LookupOverlayDialog"
};

var ForecastRoleUser = {
'pUSER' : "user",
'FORECAST_SHARE_RADIO' : "forecastSharingRadios",
'pCAN_SHARE' : "allowMgrFctSharing"
};

var OppSalesTeamRowEdit = {
'SPLIT_PERCENTAGE_LABEL' : "splitPercentage_row",
'IS_SPLIT_LABEL' : "isSplit_row",
'SPLIT_AMOUNT_LABEL' : "splitAmount_row",
'ROW_TYPE_LABEL' : "rowType_row",
'SUMMARY_ROW_ID' : "stt_summaryRow",
'USER_LOOKUP_ID_LABEL' : "userLookup_row",
'SPLIT_NOTE_LABEL' : "splitNote_row",
'ROW_ID_LABEL' : "salesTeam_row"
};

var IFrameElement = {
'EmptyRelatedListDoc' : "emptyHtmlDoc.html",
'BLANK_SRC' : "javascript: \'\'"
};

var DetailElement = {
'DEFAULT_DETAIL_ELEMENT_ID' : "ep",
'DEFAULT_ERROR_DIV_ID' : "errorDiv_ep",
'TOP_BUTTON_ROW' : "topButtonRow",
'BOTTOM_BUTTON_ROW' : "bottomButtonRow"
};

var TaskOwnerLookup = {
'pLOOKUP_UROG_SUFFIX' : "_lkurogid",
'DONE_BUTTON_ID' : "doneButton"
};

var DatePickerIds = {
'DOM_ID' : "datePicker",
'MONTH_PICKER' : "calMonthPicker",
'TABLE_ID' : "datePickerCalendar",
'YEAR_PICKER' : "calYearPicker"
};

var SectionElement = {
'LEFT_TABLE_CLASS' : "detailList"
};

var BusinessHoursPageConstants = {
'p24X7_CHECKBOX' : "has24x7"
};

var EmailAuthorConstants = {
'EMAIL_ADDR_DELIM' : "; "
};

var AjaxGetFieldTreeChildren = {
'FORMULA_TYPE' : "formulaType",
'NODE_LIST' : "nodeList",
'NODE_KEY' : "nodeKey"
};

var UserDeactivate = {
'pREMOVE_FROM_CLOSED_OPP_TEAMS' : 2,
'pREMOVE_FROM_ACCOUNT_TEAMS' : 1,
'pREMOVE_FROM_OPEN_OPP_TEAMS' : 3,
'pSPLITS_REMOVAL_NOTE' : 4
};

var InlineEditConstants = {
'FIELD_REQUIRED' : "required",
'MASS_EDITABLE' : "massEditable",
'VALIDATION_ERRORS' : "validationErrors",
'NULLABLE' : "nullable",
'FIELD_STATE' : "state",
'LAYOUT_INFO' : "layoutInfo",
'IS_PERSON' : "isPerson",
'FIELD_ID' : "fieldId",
'MAX_SAVE' : 200,
'COLUMN_NAME' : "columnName",
'COLUMN_ID' : "columnId",
'NON_SPECIFIC_ERRORS' : "nonSpecificErrors",
'OVERRIDE_TYPE' : "overrideType",
'ROLODEXABLE' : "useRolodex",
'SUCCESS' : "success",
'IS_TASK' : "isTask",
'INNER_ID' : "_ileinner",
'ENTITY_ID' : "entityId",
'FIELD_VALUE' : "initialValue",
'EDITABLE' : "editable",
'LAST_MOD' : "sysMod",
'CELL_ID' : "_ilecell",
'SAVED' : "saved",
'FIELD_TYPE' : "fieldType",
'SAVE_BUTTON' : "inlineEditSave",
'FIELD_DATA' : "fields",
'IDS' : "recordIds",
'ENTITY_TYPE' : "entityType",
'CANCEL_BUTTON' : "inlineEditCancel",
'NAME_LABEL' : "nameLabel",
'SORTABLE' : "isSortable",
'COLUMN_LABEL' : "label",
'DYNAMIC_DATA' : "dynamicData"
};

var CreateNewList = {
'DHTML_ID' : "newEntityList"
};

var SetupTreeNodeConstants = {
'COOKIE_KEY' : "setupopen"
};

var CriteriaInputConstants = {
'pOP' : "critop",
'pCOL' : "critfld",
'FILTER_SECTION_ID' : "filterSection",
'pFIELD_VAL' : "critfld_val",
'pVAL' : "pVAL",
'pLOOKUP' : "pLOOKUP",
'SHOW_SUMMARY_FILTER' : "filterControl"
};

var EmailCCBccLookupConstants = {
'CC_NAME_ID' : "cc_name",
'CC_ID' : "cc",
'ADDITIONAL_TO_ID' : "additional_to",
'BCC_ADDR_ID' : "bcc_addr",
'BCC_ID' : "bcc",
'ADDITIONAL_TO_NAME_ID' : "additional_to_name",
'ADDITIONAL_TO_ADDR_ID' : "additional_to_addr",
'BCC_NAME_ID' : "bcc_name",
'REF_ID' : "ref",
'CC_ADDR_ID' : "cc_addr"
};

var SearchSettingsConstants = {
'SIDEBAR_SEARCH_ENTITY_PICKER_ID' : "enableSidebarSearchEntityPicker",
'DEFAULT_SEARCH_ENTITY_CHECKBOX_ID' : "defaultSearchEntityCheckbox",
'DEFAULT_SEARCH_ENTITY_PICKLIST_ID' : "defaultSearchEntityPicklist"
};

var MultiSelectList = {
'pIDS' : "selectedIds",
'pFILTER_TYPE' : "filterType",
'availableTableId' : "availableTable",
'availableFrameId' : "available",
'pUNSAVED_IDS' : "unsavedIds",
'pTOTAL_ROW_COUNT_FILTER' : "msl_totalRowCountFilter",
'selectedFrameId' : "selected",
'availableCheckboxPrefix' : "chk_",
'nameCellPrefix' : "name_",
'availableRowPrefix' : "row_",
'allOrNoneCheckbox' : "allOrNone",
'pTOTAL_ROW_COUNT' : "msl_totalRowCount",
'selectedCheckboxPrefix' : "uch_",
'listEmptyLabelId' : "listEmptyLabel",
'selectionsTableId' : "selections",
'selectedRowPrefix' : "sel_",
'selectLabelId' : "selectLabel",
'deselectLabelId' : "deselectLabel"
};

var BlowoutServlet = {
'SUCCESS' : "success",
'BLOWOUT' : "blowout",
'SUFFIX' : "suf",
'SERVLETURL' : "/_ui/system/scheduler/cron/ScheduleBlowoutServlet"
};

var CSRFConstants = {
'CSRF_TOKEN' : "_CONFIRMATIONTOKEN"
};

var AjaxLoadPLAServlet = {
'TYPE' : "type",
'PAGE_SIZE' : "pageSize"
};

var FilterEditPageConstants = {
'pSEARCH_ANCHOR' : "searchAnchor"
};

var EmailTemplatePreviewConstants = {
'REQUIRED_BLOCK_CLASS' : "requiredBlock",
'ID_REQUIRED_BLOCK_ID' : "_id_required_block",
'LOOKUP_REQUIRED_BLOCK_ID' : "_lookup_required_block"
};

var InlineHelp = {
'CLASS_NAME' : "helpButton",
'ORB' : "helpOrb",
'DISPLAY_DIV_CLASS' : "helpText",
'CLASS_NAME_HOVER' : "helpButtonOn",
'ID_SUFFIX' : "_help"
};

var SchedulePage = {
'pNotifyMe' : "nm",
'pIsOffPeak' : "isoffpeak",
'pBlowout' : "bout",
'pNotifyOthers' : "no",
'pJobType' : "jt",
'pDuelOuter' : "duelOuter",
'pEmailUrog' : "eurog"
};

var ListView = {
'CHECKBOX_ID' : "ids",
'DEFAULT_ROWS_PER_PAGE' : 50,
'ID_COLUMN' : "LIST_RECORD_ID",
'SELECT_ALL_BOX_ID' : "allBox",
'ACTION_COLUMN' : "ACTION_COLUMN"
};

var OpportunitySalesTeamEdit = {
'SPLIT_AMOUNT_TOTAL_ID' : "splitAmtPer",
'SPLIT_TOTAL_ID' : "splitTotal",
'SALES_TEAM_MEMBER_TABLE_ID' : "stt",
'SPLIT_TOTAL_PER_ID' : "splitTotPer"
};

var TagConstants = {
'TAG_EDIT_LIST' : "tag_edit_list",
'BROWSER_SEARCH_HEADER_CLASS' : "pbTagBrowserSearch",
'TAG_DROP_DOWN_CONTENTS_ID' : "tag_drop_down_contents",
'BROWSER_LIST_ID' : "browseTags",
'BROWSER_TAG_TABLE_ID' : "browseTagsTable",
'EDIT_AREA_ID' : "tag_edit_area",
'TAG_DISPLAY_CONTAINER' : "tag_display_container",
'TAG_RESULTS_ID' : "tagResults",
'TAG_VALUE_FOR_UPDATE' : "tValForUpdate",
'ROLODEX_SEARCH_VALUE' : "-10",
'HIDING_PUBLIC_SECTION_ID' : "layoutPublicEditSection",
'CHANGE_TAGS_NAMES' : "changeTagsNames",
'TAG_SEARCH_FIELD' : "tagsSearch",
'TAG_MERGE_CHECK' : "/ui/tag/TagMergeCheckServlet",
'ERROR_DIV_ID' : "tagHomeErrorDiv",
'TAG_RESULTS_BODY_ID' : "tagListBody",
'TAG_EDIT_ERROR_ID' : "tag_edit_error",
'TAG_DROP_DOWN_ID' : "tag_drop_down",
'LOOKUP_TAGS_PAGE' : "/ui/tag/LookupTagsPage",
'TAG_ID_LIST' : "tIdList",
'TAG_HEADER' : "tag_header",
'TAG_SEARCH_RESULTS_URL' : "/search/TagSearchResults",
'SAVED_TAG_SEARCH' : "savedTagSearch",
'EDIT_SECTION_ID' : "editSectionId",
'NOTIFY_MSG_ID' : "successNotifyId",
'PUBLIC_TAG_IDS_ELEM' : "pTagIds",
'TAG_SAVE_ID' : "tag_save",
'HIDING_SECTION_ID' : "layoutEditSection",
'TAG_SUMMARY_ID' : "tagSummary",
'PUBLIC_TAG_NAMES_ELEM' : "pTagNames",
'TAG_DISPLAY_LIST' : "tag_display_list",
'TAG_ROLODEX_ID' : "tagRolodexId",
'TAG_SET_HAS_RECORDS' : "tagSetHasRecords",
'CHANGE_TAGS_IDS' : "changeTagsIds",
'HIDDEN_TAG_LIST' : "hidden_tag_list",
'TAG_IDS_ELEM' : "tagIds",
'SAVE_TAGS_PAGE' : "/ui/tag/SaveTagsPage",
'HIDDEN_TAG_ID_LIST' : "hidden_tag_id_list",
'TAG_UPDATE_STRING' : "tagUpdate",
'TAG_EDIT_ID' : "tag_edit",
'TAG_NAMES_ELEM' : "tagNames",
'EDIT_TAGS_PAGE' : "/ui/tag/TagsEditPage",
'pTAG_SCOPE_MODE' : "scopeMode",
'TAG_EDIT_TEXT_ID' : "tag_edit_text",
'IS_DELETE' : "isDelete",
'TAG_CANCEL_ID' : "tag_cancel"
};

var BounceEmailConstants = {
'HIDDEN_BOUNCE_DATE' : "hidden_bounce_date",
'HIDDEN_EMAIL_ADDRESS' : "hidden_email_address",
'HIDDEN_BOUNCE_REASON' : "hidden_bounce_reason"
};

var RequestInfo = {
'pSID' : "sid"
};

var LookupsUi = {
'LOOKUPS' : "lookups",
'FIELD' : "field",
'PATH' : "path"
};

var CrtLookupConstants = {
'LOOKUP_HEADER' : "lookupInnerHeader",
'CONTROL_ELEM_1' : "controlLinks1",
'LOOKUP_DEPTH_LIMIT' : 4,
'LOOKUP_ELEM' : "lookupBox",
'PATH_ELEM' : "pathBox"
};

var StageManager = {
'pWIZARD_RET_URL' : "wizardRetUrl"
};

var ActivityReminderPage = {
'pCLASS_NAME' : "ui.core.activity.ActivityReminderPage"
};

var MouseOverElement = {
'DEFAULT_CLASS_INNER' : "mouseOverInfo",
'DEFAULT_CLASS' : "mouseOverInfoOuter"
};

var ActivityReminderConstants = {
'pTEST' : "test",
'DISMISS_ID' : "dismiss",
'SUMMARY_ID' : "summary",
'SNOOZE_TIME_ID' : "snooze_time",
'DUE_MINUTES_ID' : "minutes",
'ALL_DAY_ATTR' : "all_day",
'DUE_TIME_ATTR' : "due_time",
'DISMISS_ALL_ID' : "dismiss_all",
'SNOOZE_ID' : "snooze",
'pAT' : "at",
'REMINDERS_OK' : "reminders_ready",
'pSNOOZED_AT' : "snoozed_at",
'REMINDER_ID' : "reminder",
'REMINDERS_NONE' : "reminders_none_active"
};

var ForecastSettings = {
'pFORECAST_SHARING' : "forecastSharing",
'pALLOW_FM_SHARING' : "allowFMSharing"
};

var ColorInputConstants = {
'COLOR_BOX_CSS' : "colorBox",
'ERROR_COLOR_BOX_CSS' : "errorColorBox"
};

var AdvancedCurrencyEnable = {
'pENABLE' : "enable",
'enableButton' : "enableButton"
};

var AjaxLoadPLAForRecordTypeServlet = {
'RECORD_TYPE_ID' : "rtId"
};

var AjaxLoadPLAForPageServlet = {
'PAGE_NUM' : "pageNum"
};

var CustomMotifDefinitionPageConst = {
'MOTIF_ICON_PARAM' : "file_id",
'COLOR_ELEMENT' : "ce"
};

var DeveloperSettings = {
'LICENSE_MGR_CHOICE_STR' : "licenseMgr"
};

var ReportsFch = {
'FLOATING_HEADER' : "floatingHeader",
'HEADER_ROW' : "headerRow",
'FCH_AREA' : "fchArea"
};

var findSimilarQueryPage = {
'FIND_PROVIDER' : "findSimilarProvider",
'SEARCH_QUERY_STRING' : "srch"
};

var UiData = {
'pCANCEL_URL' : "cancelURL",
'pRET_URL' : "retURL",
'pSAVE_URL' : "saveURL"
};

var SetupSearchElement = {
'ATT_SEARCH_TEXT' : "searchText",
'SETUP_SEARCH_PARAM' : "setupSearch"
};

var DurationInputElement = {
'pMINUTES_NAME' : "mi",
'pHOURS_NAME' : "hh"
};

var CompactLayoutUiConst = {
'showItemsLeft' : "showItemsLeft",
'showItemsRight' : "showItemsRight",
'switchColumnToLeft' : "switchColumnLeft",
'hideItemsLeft' : "hideItemsLeft",
'hideItemsRight' : "hideItemsRight",
'switchColumnToRight' : "switchColumnRight",
'saveButtonId' : "saveButton"
};

var MotifInputElementConst = {
'FIELD_NAME_MOTIF' : "motifName",
'MOTIF_ELEMENT_SUFFIX' : "motifElement",
'FIELD_NAME_ICON' : "motifIcon",
'FIELD_NAME_DESCRIPTION' : "motifClass"
};

var DesktopSidebarComponents = {
'GOOGLETALK_CONTAINER_ID' : "googleTalk",
'SOFTPHONE_CONTAINER_ID' : "softphoneContainer",
'MRU_LIST_CONTAINER_ID' : "mruList"
};

var EventObject = {
'ONE_DAY_IN_MINUTES' : 1440
};

var MultiLookupInputElement = {
'MULTI_LOOKUP_SELECT_SUFFIX' : "_mlktp"
};

var SoftphoneLayoutEditorConstants = {
'RESULT_FIELDS_KEY' : "resultFields",
'CALL_TYPE_PREFIX' : "callType_",
'XSLT_RELATED_OBJS_CSS' : "relatedObjects",
'HIDDEN_IFRAME_ID' : "previewIframe",
'FLIPPY_PREFIX' : "flippy_",
'CALL_TYPE_PREVIEW_PREFIX' : "callTypePreview_",
'FIRST_FLIPPY_CSS' : "firstFlippy",
'FLIPPY_CONTROL_PREFIX' : "control_",
'XSLT_INFO_FIELDS_CSS' : "infoFields",
'LISTING_PREFIX' : "listing_"
};

var ChangePasswordConstants = {
'pANSWER_ERROR_ELEM' : "answerContainsPassword",
'pNEW_PASSWORD_CONFIRMATION_ICON_ELEM' : "passVerify",
'pNEW_PASSWORD_CONFIRMATION_ELEM' : "p6",
'pQUESTION_ELEM' : "p2",
'pOLD_PASSWORD_ELEM' : "p4",
'pNEW_PASSWORD_ELEM' : "p5",
'pANSWER_ELEM' : "p3",
'pANSWER_ICON_ELEM' : "answerVerify",
'pNEW_PASSWORD_STRENGTH_ELEM' : "passStrength",
'pNEW_PASSWORD_ICON_ELEM' : "strengthImage"
};

var ForecastSummaryPage = {
'pLOOKUP_INPUT_ENTERED' : "lookupEntered"
};

var vaSelectElementConst = {
'UP_CLASS' : "up",
'DOWN_CLASS' : "down"
};

var MCXHRParams = {
'pLoadObjId' : "LOI",
'pIsSuccess' : "isSuccess",
'pTestResultRecordCount' : "recordCount",
'pSaveObjParentId' : "SPI",
'pTestResultDataSize' : "dataSize",
'pScope' : "scope",
'pLoadObjType' : "LOT",
'pTotalsElement' : "totalsElement",
'pTestResultConfigError' : "configError",
'pCollisionParam' : "LMT",
'pData' : "data",
'pSaveObjId' : "SOI",
'pQSTestResults' : "qsTestResults",
'pTestResultQSID' : "id",
'pAction' : "ACT",
'pSaveObjType' : "SOT",
'pFilterItemCount' : "itemCount"
};

var TagMode = {
'PUBLIC' : "public",
'PERSONAL' : "personal"
};

var AjaxValidateFormula = {
'RANGE_KEY' : "range",
'VALID_KEY' : "valid"
};

var UserInterfaceUI = {
'pNEW_LIST_VIEW_NAME' : "newListView",
'pCLICK_AND_CREATE_ON_CALENDAR_NAME' : "clickAndCreateOnCalendar",
'pINLINE_SCHEDULING_NAME_MESSAGE' : "inlineSchedulingMessage",
'pDRAG_AND_DROP_ON_CALENDAR_NAME' : "dragAndDropOnCalendar",
'pINLINE_SCHEDULING_NAME' : "inlineScheduling"
};

var CrtLayoutElement = {
'cFIELD_IN_SECTION' : "#CCCCCC",
'pVALUE' : "val",
'SECTION_NAME' : "name",
'SECTION_CAN_EDIT_LABEL' : "canEditLabel",
'MAX_DISPLAY_FIELD_LENGTH' : 15,
'cFIELD_USED_FONT' : "#B0B0B0",
'CSS_CLASS_LAYOUT_ITEM_SEPARATOR' : "sepCell",
'LAYOUT_NAME' : "name",
'pSAVE_AND_CLOSE' : "saveAndClose",
'ACTIONREF_NAME' : "name",
'COLUMN_NAME' : "columnName",
'LAST_SEC_SEP_DIV' : "LAST_SEC_SEP_DIV",
'SECTION_SORT_ORDER_HORIZONTAL' : "h",
'cSEPARATOR_ON' : "#000000",
'SECTION_NUM_COLUMNS' : "numColumns",
'SECTION_SORT_ORDER' : "sortOrder",
'cFIELD_UNUSED' : "#CCCCAA",
'cFIELD_SELECTED' : "#6699CC",
'SECTION_DIV_SUFFIX' : "availSectionDiv",
'ITEM_CUSTOMLABEL' : "customLabel",
'ACTIONREF' : "actionRef",
'ITEM_LAYOUT_IDS' : "lIds",
'CSS_CLASS_LAYOUT_ITEM' : "itemCell",
'ITEM_BEHAVIOR' : "behavior",
'SECTION_HEADER_ID_PREFIX' : "sec_",
'ITEM_NAME' : "name",
'ITEM_POS_X' : "xPos",
'XML_FORM_NAME' : "submitForm",
'SCROLL_BUFFER_ID' : "scrollBuffer",
'cFIELD_EMPTY' : "#FFFFFF",
'LAYOUT_FIELDS_LIMIT' : 1000,
'SECTION_MASTER_LABEL' : "masterLabel",
'SECTION_TABLE_ID_PREFIX' : "table",
'ITEM_HEIGHT' : "height",
'SECTION_ID' : "sectionId",
'ITEM_WIDTH' : "width",
'COLUMN_ID' : "columnId",
'DEFAULT_NUM_COLS' : "defaultNumCols",
'HOVER_DIV' : "MOUSE_HOVER_DIV",
'SECTION_EDIT_HEADING' : "editHeading",
'cAVAILABLE_HIGHLIGHT' : "#000000",
'MAIN_TABLE_DIV_ID' : "mainTableDiv",
'ITEM' : "item",
'ITEM_ID' : "itemId",
'SECTION_SEP_DIV_PREFIX' : "LayoutSectionSeparator_",
'ACTIONREF_ORDER' : "order",
'NUM_LAYOUT_COLS' : 4,
'FIELD_TYPE_SELECT_NAME' : "availableDropDown",
'SEPARATOR_PREFIX' : "rp_",
'SECTION' : "section",
'CSS_CLASS_LAYOUT_CELL' : "layoutCell",
'cFIELD_USED' : "#EEEEEE",
'SECTION_AVAIL_WRAPPER_ID' : "availableSectionWrapper",
'ITEM_DEFAULT_CHECKED' : "defaultChecked",
'AVAIL_CELL' : "availCell",
'ITEM_SHOWLABEL' : "showLabel",
'ITEM_SHOWSCROLLBARS' : "showScrollbars",
'LEFT_SECTION_ID' : "layoutdndLeft",
'COLUMN' : "column",
'ITEM_TYPE' : "itemType",
'SECTION_DETAIL_HEADING' : "detailHeading",
'ROOT_CONTAINER' : "root"
};

var MailmergeTemplateSelectElementConst = {
'TEMPLATE_DESCRIPTION' : "mmtse_description",
'TEMPLATE_VIEW_BUTTON' : "mmtse_preview",
'TEMPLATE_ID' : "mmtse_id",
'TEMPLATE_TITLE' : "mmtse_title"
};

var GoogleDocCreator = {
'FORM_NAME' : "googleDocForm",
'UPLOAD' : 1,
'DOC_NAME' : "docName",
'DOC_UPLOAD_NAME' : "docUploadName",
'DOC_UPLOAD' : "docUpload",
'DOC_TYPE' : "docType",
'DIALOG_ID' : "DocNameInputId",
'CREATE' : 0,
'METHOD' : "method",
'PARENT_ID' : "parentId"
};

var FilterSelectionElement = {
'pCOLUMN' : "col",
'ON_LOAD_CRITERIA' : "onLoadCriteria",
'pOPERATOR' : "oper",
'pFILTER_VALUE' : "fval"
};

var TaskUi = {
'ASSIGNEE_SEPARATOR' : ",",
'pLOOKUP_BUTTON_MULTI_OWNER_SUFFIX' : "m",
'pSHOW_PREFERENCE' : "show_pref",
'MAX_TMU_ASSIGNEES' : 100,
'pNOTIFY_PREFERENCE_GROUP_ELEMENT' : "prefEl",
'pMAX_ASSIGNEE_TEXT_LENGTH' : 200,
'pLOOKUP_SUMMARY_SUFFIX' : "_sum",
'pLOOKUP_DISPLAY_SUFFIX' : "_dsp"
};

var DynamicContent = {
'pTYME' : "tyme",
'pERROR_TITLE' : "errorTitle",
'pCOOKIE_PARAM' : "cookieParam",
'pERROR_DESC' : "errorDesc"
};

var TimePickerInputElementConstants = {
'EMPTY_TIME_STANDIN' : "HH:MM"
};

var RoleTreeCookieConstants = {
'COOKIE_KEY' : "roleopen"
};

var HTPortal = {
'pORG_ID' : "orgId",
'pID' : "id",
'pTRACK' : "track",
'pTARGET' : "target",
'pCLASS_NAME' : "cname",
'pSECTION' : "section",
'pCLASS_DAY' : "R_DAY",
'pSELECT_LOCATION' : "sel_loc",
'pBODY' : "body",
'pLOCATION' : "loc",
'pFEATURE' : "feature"
};

var EditPageConstants = {
'pCANCEL' : "cancel",
'pEDIT_PAGE' : "editPage",
'pSAVE_CLOSE' : "save_close",
'pSAVE_ATTACH' : "save_attach",
'pSAVE_NEW_URL' : "save_new_url",
'pSAVE_NEW' : "save_new",
'pSAVE' : "save",
'pQUICK_SAVE' : "quick_save"
};

var EventUi = {
'START_TIME_PARAM_NAME' : "startTimeId",
'REMINDER_DATE_TIME_ID' : "reminder_dt",
'PRIVATE_CHECKBOX_PARAM_NAME' : "privateCheckboxId",
'REMINDER_SET_ID' : "reminder_select_check",
'ALL_DAY_PARAM_NAME' : "allDayId",
'WHAT_LINK_PARAM_NAME' : "whatLinkId",
'WHAT_NAME_PARAM_NAME' : "whatNameId",
'REMINDER_DATE_TIME_PARAM_NAME' : "reminderDateTimeTimeId",
'pONLINE_HOVER' : "olmhov",
'ALL_SUBGROUP_DIVS' : "dwmy",
'WHO_ID_PARAM_NAME' : "whoId",
'START_DATE_PARAM_NAME' : "startDateId",
'WHO_TYPE_PARAM_NAME' : "whoTypeId",
'RECURRING_EVENT_PARAM_NAME' : "isRecurringId",
'RECURRENCE_PATTERN_DIV' : "recpat",
'LEAD_PREFIX_PARAM_NAME' : "leadPrefix",
'pADD_INVITEE_ID' : "addInvId",
'REMINDER_SELECT_ID' : "reminder_lt",
'pONLINE_MEETING' : "onlinemtg",
'VISIBLE_IN_SS_PARAM_NAME' : "isVisibleInSelfServiceId",
'WHAT_ID_PARAM_NAME' : "whatIdId",
'WHAT_TYPE_PARAM_NAME' : "whatTypeId",
'END_DATE_PARAM_NAME' : "endDateId",
'pISPERSONACCOUNT' : "pip",
'END_TIME_PARAM_NAME' : "endTimeId"
};

var EmailAddrEditConstants = {
'pSAVE_CANCEL' : "saveCancel",
'pPASS_IN_EMAIL_ADDRESS' : "pass_in_email_address"
};

var EventPage = {
'DISABLED_RECURRENCE_MSG_DIV' : "DisabledRecurrenceMsgDiv",
'CALENDAR_IFRAME_ID' : "calendarIFrame"
};

var MenuButtonElement = {
'BUTTON' : "Button",
'GO_BUTTON' : "Go",
'MENU' : "Menu",
'SELECT' : "Select"
};

var CrtConstants = {
'PICKLIST_VALUE_TABLE_FIELD_SEPARATOR' : '.',
'OBJECT_PREFIX' : "o",
'MAX_OBJECTS' : 4,
'PICKLIST_VALUE_ID_SEPARATOR' : '|'
};

var Activity = {
'WHO_BUTTON_ID' : "whobtn",
'pNEW_ATTACHMENTS' : "newatt",
'pATT_WARNING' : "attWarning"
};

var ColorPickerConstants = {
'HEX_VIEW_ID' : "colorPickerHexView",
'DOM_ID' : "colorPicker",
'COLOR_VIEW_ID' : "colorPickerColorView"
};

var CrtObjectElement = {
'TERMINAL_OBJECT_WARNING' : "endWarning",
'REMOVE_OBJECT_LINK' : "remove",
'INNER_JOIN_SELECT' : "inner_select",
'GHOST1' : "ghost1",
'MAX_OBJECTS_WARNING' : "warning",
'LEVEL' : "level",
'ELBOW_INNER' : "elbow_inner",
'ELBOW_OUTER' : "elbow_outer",
'EST_OBJECT_LABEL' : "estObjLabel",
'JOIN_RADIO' : "radio",
'INNER_JOIN_OPTION' : "inner_join_option",
'GHOST_ELBOW' : "ghost_elbow",
'GHOST0' : "ghost0",
'OUTER_JOIN_SELECT' : "outer_select"
};

var MCFilterPaneParams = {
'pORDER_BY_DIV' : "orderBySection",
'pNO_LIMIT' : "noLimit",
'pMAX_RECORD_RADIO' : "maxRecordRadio",
'pSCOPE' : "ofscope",
'pSET_LIMIT' : "setLimit",
'NONE_SCOPE_VALUE' : "-1"
};

var BodyLayout = {
'FOOTER_DIV_ID' : "bodyFooter",
'PAGE_HEADER_ID' : "AppBodyHeader",
'BODY_CELL_ID' : "bodyCell",
'BODY_TABLE_ID' : "bodyTable"
};

var HoverTooltipElement = {
'DEFAULT_CLASS_TEXT' : "mouseOverText"
};

var JSPDispatcher = {
'STANDARD_PACKAGE' : "ui",
'NONSTANDARD_PACKAGE_PREFIX' : "_ui/",
'PACKAGE_MARKER' : "p/"
};

var InlineScontrolElement = {
'DEFAULT_WIDTH' : -100,
'DEFAULT_HEIGHT' : 200
};

var ActivityReminderRefreshPage = {
'pCLASS_NAME' : "ui.core.activity.ActivityReminderRefreshPage"
};

var AjaxServlet = {
'CSRF_PROTECT' : "while(1);\n",
'ERROR_MSG_KEY' : "errMsg"
};

var RuleFilterPageConstants = {
'NO_REASSIGN_SUFFIX' : "_noReassign"
};

var FieldTreeConstants = {
'SELECT_ID' : "FieldTreeSelect"
};

var Udd = {
'EMPTY_KEY' : "000000000000000"
};

var ProfileEditConstants = {
'CRUD_DELETE' : "crudDelete",
'CRUD_UPDATE' : "crudUpdate",
'CRUD_CREATE' : "crudCreate",
'CRUD_READ' : "crudRead"
};

var CaptchaVerifierServlet = {
'RESPONSE_PARAM' : "resp",
'SERVLET_NAME' : "common.html.captcha.CaptchaVerifierServlet",
'VALID_KEY' : "valid",
'CLIENT_ERROR_PARAM' : "error",
'CHALLENGE_PARAM' : "chal"
};

var AbstractAutoCompleteServlet = {
'AUTOCOMPLETE_USED_SUFFIX' : "_acused",
'pINPUT' : "inputString"
};

var EditEventMultiUserCalendarElementConstants = {
'EDIT_PAGE_CALENDAR' : "editEventCalendar"
};

var SearchRelatedList = {
'FILTER_FIELDS_PARAM' : "sFltrFields",
'ALL_STATES_PREFIX' : "allStates_",
'SearchUserLayoutServletName' : "UserSearchListLayout",
'COMBO_BUTTON_ID' : "comboButton",
'SearchFilterInfoServletName' : "SearchFilterInfo",
'COLUMN_SELECTOR_PREFIX' : "selector_",
'LIST_LAYOUT_TYPE_PARAMETER' : "layoutType",
'ERROR_DIV_ID_PREFIX' : "srchErrorDiv_",
'SEARCH_ACTION_IDENTIFIER_PARAM' : "aId",
'COLUMN_PARAMETER' : "columns",
'pSEARCH' : "search",
'pSEARCH_STR' : "str",
'ENTITY_PARAMETER' : "entity",
'SEARCH_IDENTIFIER_PARAM' : "searchId",
'PER_ENTITY_VALUE' : "perEntityValue",
'FILTER_FIELDS_SAVE_PREFIX' : "save_filter_",
'pENTITY_ALL' : "0",
'ShouldNotLookUp' : "noLookUp",
'FILTER_FIELD_FORM_PREFIX' : "field_name_form_",
'FILTER_FIELDS_PREFIX' : "field_name_"
};

var AjaxGetUsersInGroups = {
'pOWNER_ID_LIST' : "ownerIdList",
'pCLASS_NAME' : "common.ownership.group.AjaxGetUsersInGroups",
'pNUM_USERS' : "numUsers",
'pINVALID_GROUPS_MESSAGE' : "invalidGroups",
'pOWNER_NAME_LIST' : "ownerNameList"
};

var SidebarConstants = {
'HANDLE_ID' : "handle",
'SIDEBAR_PINNED_COOKIE' : "sidebarPinned",
'pSEARCH_SIDEBAR_STR' : "sbstr",
'PIN2_INDICATOR_ID' : "pinIndicator2",
'PIN_INDICATOR_ID' : "pinIndicator",
'SIDEBAR_DIV_ID' : "sidebarDiv"
};

var ColumnTypeConstants = {
'PERSONNAME_LASTNAME_OFFSET' : 2,
'PERSONNAME_FIRSTNAME_OFFSET' : 1,
'DEFAULT_STATE_LENGTH' : 20,
'ADDRESS_STREET_OFFSET' : 0,
'DEFAULT_CITY_LENGTH' : 40,
'PERSONNAME_SALUTATION_OFFSET' : 0,
'DEFAULT_ZIP_LENGTH' : 20,
'DEFAULT_SALUTATION_LENGTH' : 40,
'ADDRESS_POSTAL_CODE_OFFSET' : 3,
'DEFAULT_LASTNAME_LENGTH' : 80,
'DEFAULT_FIRSTNAME_LENGTH' : 40,
'DEFAULT_COUNTRY_LENGTH' : 40,
'ADDRESS_COUNTRY_OFFSET' : 4,
'ADDRESS_CITY_OFFSET' : 1,
'ADDRESS_STATE_OFFSET' : 2,
'DEFAULT_TEXTNAME_LENGTH' : 255,
'DEFAULT_STREET_LENGTH' : 255
};

var Desktop = {
'AgentConsoleY' : "AgentConsoleY",
'AgentConsoleS' : "AgentConsoleS",
'pGOTO_ID' : "goToId",
'RESIZE_WIDTH' : "resizeWidth",
'pGOTO_URL' : "goToUrl",
'AgentConsoleX' : "AgentConsoleX",
'BROWSER_MAX_URL' : "2048",
'AgentConsoleFE' : "AgentConsoleFE",
'SIDEBAR_NORMAL_WIDTH_STYLE_PX' : "200",
'IS_DESKTOP' : "isdtp"
};

var EditElement = {
'FIELD_NAME_LAST' : "name_last",
'pOLD_NAME_SUFFIX' : "_lkold",
'SELECTED_ID_SUFFIX' : "_selected",
'FIELD_NAME_ZIP' : "zip",
'pBASE_NAME' : "lknm",
'pTYPE_SUFFIX' : "_lktp",
'FIELD_NAME_SALUTATION' : "name_salutation",
'FIELD_NAME_CITY' : "city",
'FIELD_NAME_COUNTRY' : "country",
'pID_SUFFIX' : "_lkid",
'STREET_NUM_COLS' : 27,
'FIELD_NAME_FIRST' : "name_first",
'FIELD_NAME_STREET' : "street",
'FIELD_NAME_STATE' : "state",
'CHECKBOX_SUFFIX' : "_chkbox",
'STREET_NUM_ROWS' : 2,
'ERROR_CLASS' : "error",
'UNSELECTED_ID_SUFFIX' : "_unselected"
};

var EmailRelayConstants = {
'EMAIL_RELAY_TLS_SETTING_ID' : "email_relay_tls_setting",
'RESTRICT_TO_DOMAINS_ID' : "restrict_to_domains",
'ACTIVATE_RESTRICT_TO_DOMAINS_ID' : "activate_restrict_to_domains",
'EMAIL_HOST_PORT_ID' : "email_host_port",
'EMAIL_HOST_ID' : "email_host",
'ACTIVATE_EMAIL_RELAY_ID' : "activate_email_relay",
'RESTRICT_TO_DOMAINS_HIDDEN_ID' : "restrict_to_domains_hidden"
};

var BrowserSettingsWarningElement = {
'NEVER_SHOW_AGAIN_ID' : "browserSettingsWarningGoAway",
'cBrowserSettings' : "numReqs",
'BROWSER_SETTINGS_WARNING_ID' : "browserSettingsWarning",
'MORE_INFO_ID' : "browserSettingsWarningMoreInfo"
};

var ReportConstants = {
'pSubTotalBy0' : "subtotalBy0"
};

var CreateNewElement = {
'DOM_ID' : "createNew"
};

var ForecastSharingPrefPopup = {
'CAN_SHARE_RADIO' : "enableRadio",
'pIS_FCT_SHARE_ENABLED' : "isFctShareEnabled",
'DISABLE_CHECKBOX' : "disableCheckbox"
};

var SummaryFieldConstants = {
'OPERATION_CONTAINER_ID' : "operationCtr"
};

var NewLayoutEditor = {
'BLANK_ID' : "__BLANK",
'STD_BTN_PREFIX' : "BTN__"
};

var ScheduleElement = {
'pPrefTimeDiv' : "prefTime",
'pPrefTimeLabelDiv' : "prefTimeLabel",
'pDailyEveryNDays' : "dn",
'pMonthlyOnDayN' : "mdom",
'pPrefTime' : "pst",
'pEndDate' : "end",
'pStartDate' : "start",
'pPrefTimeLoadingDiv' : "prefTimeLoad",
'pFreq' : "freq",
'pMonthlyOnNthDay' : "mond",
'pDailyRec' : "dr",
'pOtherPrefTimeLabelDiv' : "otherPrefTimeLabel",
'pDayOfWeek' : "ww",
'pOuterBox' : "outerBox",
'pMonthlyRec' : "mr",
'pMonthlyOnNDayOfWeek' : "mdn"
};

var GoogleTalkConstants = {
'MIN_EXPANDED_HEIGHT' : 22,
'EXPANDED_HEIGHT' : 400,
'HEIGHT_COOKIE' : "gTalkHeight",
'COLLAPSED_HEIGHT' : 0,
'COLLAPSED_COOKIE' : "gTalkCollapsed"
};

var PortalStyleConfigEditorConstants = {
'PARAM_PREFIX' : "p_"
};

var SalesTeamRowTypeEnum = {
'EXISTING_DELETED' : "Existing_Deleted",
'NEW_DELETED' : "New_Deleted",
'EXISTING_INACTIVE' : "Existing_Inactive",
'EXISTING' : "Existing",
'NEW' : "New"
};

var AjaxLoadFieldsForEntity = {
'pFIELD_LIST' : "fieldList",
'pENTITY_NAME' : "entity",
'pPARENT_ENTITY_NAME' : "parentEntity"
};

var TaskMassAction = {
'ROW_LIMIT' : 200
};

var ManageableInfo = {
'MORE_INFO_CLASS' : "manageableMoreInfo",
'DHTML_ID' : "manageableInfo"
};

var LayoutItemTypeEnum = {'CUSTOM_LINK':{'apiValue':'K','dbValue':'K'}
,'STANDARD_RELATED_LIST':{'apiValue':'R','dbValue':'R'}
,'PAGE':{'apiValue':'P','dbValue':'P'}
,'EMPTY_SPACE':{'apiValue':'E','dbValue':'E'}
,'TAGGING':{'apiValue':'T','dbValue':'T'}
,'STANDARD_FIELD':{'apiValue':'F','dbValue':'F'}
,'DETAIL_BUTTON_BAR':{'apiValue':'B','dbValue':'B'}
,'CUSTOM_S_CONTROL':{'apiValue':'S','dbValue':'S'}
,'CUSTOM_RELATED_LIST':{'apiValue':'L','dbValue':'L'}
,'CUSTOM_FIELD':{'apiValue':'C','dbValue':'C'}
}
;
var ColumnType = {'DUEDATE':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return DateField;},'inlineEditExtraData':['hasTime'],'datatypeLetter':'F','isDate':true,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'INTEGER':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return NumberField;},'inlineEditExtraData':null,'datatypeLetter':'N','isDate':false,'isNumber':true,'inlineEditable':true,'isCompond':false}
,'PERSONNAME':{'inlineEditFieldObject':'PersonNameField','queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':function(){return PersonNameField;},'inlineEditExtraData':['hasSalutation','reverse','picklistId','labels'],'datatypeLetter':'M','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':true}
,'DYNAMICENUM':{'inlineEditFieldObject':'DynamicEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':true,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return DynamicEnumField;},'inlineEditExtraData':['picklistId','controller','controllerLabel'],'datatypeLetter':'L','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'BLOB':{'inlineEditFieldObject':null,'queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'X','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'MULTIENUM':{'inlineEditFieldObject':'MultiEnumField','queryOperators':['e','n','u','x'],'needsLookup':true,'filterQueryOperators':['e','n'],'inlineEditFieldConstructor':function(){return MultiEnumField;},'inlineEditExtraData':['picklistId','controller','controllerLabel','height'],'datatypeLetter':'Q','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'PERCENT':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return NumberField;},'inlineEditExtraData':null,'datatypeLetter':'P','isDate':false,'isNumber':true,'inlineEditable':true,'isCompond':false}
,'STRINGPLUSCLOB':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return MultiLineTextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'J','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ADDRESSSTATE':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'S','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'DATETIME':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return DateField;},'inlineEditExtraData':['hasTime'],'datatypeLetter':'F','isDate':true,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ADDRESSCOUNTRY':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'S','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'PHONE':{'inlineEditFieldObject':'PhoneField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return PhoneField;},'inlineEditExtraData':['maxLength','formatPhone'],'datatypeLetter':'H','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'SWITCHABLE_PERSONNAME':{'inlineEditFieldObject':null,'queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':function(){return null;},'inlineEditExtraData':null,'datatypeLetter':'m','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':true}
,'TIMEONLY':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'f','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'CONTENT':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'9','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'DATEONLY':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return DateField;},'inlineEditExtraData':['hasTime'],'datatypeLetter':'D','isDate':true,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'TEXT':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'S','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'YEARQUARTER':{'inlineEditFieldObject':null,'queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'O','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':true}
,'EMAIL':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'E','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'URL':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'U','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'FAX':{'inlineEditFieldObject':'PhoneField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return PhoneField;},'inlineEditExtraData':['maxLength','formatPhone'],'datatypeLetter':'G','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ENCRYPTEDTEXT':{'inlineEditFieldObject':'EncryptedTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return EncryptedTextField;},'inlineEditExtraData':['maxLength','masked'],'datatypeLetter':'6','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'HTMLMULTILINETEXT':{'inlineEditFieldObject':'HtmlMultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return HtmlMultiLineTextField;},'inlineEditExtraData':['maxLength','isHtml'],'datatypeLetter':'5','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'BIRTHDAY':{'inlineEditFieldObject':'DateField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return DateField;},'inlineEditExtraData':['hasTime'],'datatypeLetter':'D','isDate':true,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ANYTYPE':{'inlineEditFieldObject':null,'queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'K','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'RECORDTYPE':{'inlineEditFieldObject':null,'queryOperators':['e','n'],'needsLookup':true,'filterQueryOperators':['e','n'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'7','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'BOOLEAN':{'inlineEditFieldObject':'BooleanField','queryOperators':['e','n'],'needsLookup':true,'filterQueryOperators':['e','n'],'inlineEditFieldConstructor':function(){return BooleanField;},'inlineEditExtraData':null,'datatypeLetter':'B','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'MULTILINETEXT':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return MultiLineTextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'X','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ADDRESS':{'inlineEditFieldObject':'AddressField','queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':function(){return AddressField;},'inlineEditExtraData':['showState','labels'],'datatypeLetter':'A','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':true}
,'INETADDRESS':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'W','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'ENUMORID':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':true,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'L','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'BITVECTOR':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'8','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'DIVISION':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':true,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return StaticEnumField;},'inlineEditExtraData':['picklistData'],'datatypeLetter':'I','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'ENTITYID':{'inlineEditFieldObject':'ForeignKeyField','queryOperators':['e','n','s'],'needsLookup':false,'filterQueryOperators':['e','n','s'],'inlineEditFieldConstructor':function(){return ForeignKeyField;},'inlineEditExtraData':['domain','useNewLookups'],'datatypeLetter':'Y','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'AUTONUMBER':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':null,'datatypeLetter':'V','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'DOUBLE':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return NumberField;},'inlineEditExtraData':null,'datatypeLetter':'N','isDate':false,'isNumber':true,'inlineEditable':true,'isCompond':false}
,'TEXTENUM':{'inlineEditFieldObject':'TextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return TextField;},'inlineEditExtraData':['maxLength'],'datatypeLetter':'L','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'CURRENCY':{'inlineEditFieldObject':'NumberField','queryOperators':['e','n','l','g','m','h'],'needsLookup':false,'filterQueryOperators':['e','n','l','g','m','h'],'inlineEditFieldConstructor':function(){return NumberField;},'inlineEditExtraData':null,'datatypeLetter':'C','isDate':false,'isNumber':true,'inlineEditable':true,'isCompond':false}
,'FFX_BLOB':{'inlineEditFieldObject':null,'queryOperators':null,'needsLookup':false,'filterQueryOperators':null,'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'X','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
,'HTMLSTRINGPLUSCLOB':{'inlineEditFieldObject':'MultiLineTextField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return MultiLineTextField;},'inlineEditExtraData':['maxLength','numCols','numRows','isHtml'],'datatypeLetter':'z','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'STATICENUM':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':true,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return StaticEnumField;},'inlineEditExtraData':['picklistData'],'datatypeLetter':'L','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'CURRENCYCODE':{'inlineEditFieldObject':'StaticEnumField','queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':function(){return StaticEnumField;},'inlineEditExtraData':['picklistData'],'datatypeLetter':'L','isDate':false,'isNumber':false,'inlineEditable':true,'isCompond':false}
,'SFDCENCRYPTEDTEXT':{'inlineEditFieldObject':null,'queryOperators':['e','n','l','g','m','h','c','k','s','i'],'needsLookup':false,'filterQueryOperators':['e','n','c','k','s'],'inlineEditFieldConstructor':null,'inlineEditExtraData':null,'datatypeLetter':'T','isDate':false,'isNumber':false,'inlineEditable':false,'isCompond':false}
}
;
var InlineEditState = {'EDIT':{'display':true,'cssClass':'inlineEditWrite'}
,'READONLY':{'display':true,'cssClass':'inlineEditLock'}
,'POSTONLY':{'display':false,'cssClass':''}
,'NONE':{'display':false,'cssClass':''}
}
;
var QueryOperator = {'INCLUDES':{'value':'u'}
,'STARTS_WITH':{'value':'s'}
,'EXACT_EQUALS':{'value':'a'}
,'GREATER_THAN':{'value':'g'}
,'RANGE_INCLUSIVE':{'value':'I'}
,'NOT_START_WITH':{'value':'t'}
,'NOT_EQUAL':{'value':'n'}
,'EXCLUDES':{'value':'x'}
,'LESS_OR_EQUAL':{'value':'m'}
,'GREATER_OR_EQUAL':{'value':'h'}
,'CONTAINS':{'value':'c'}
,'LESS_THAN':{'value':'l'}
,'NOT_LIKE':{'value':'j'}
,'NOT_EXACT_EQUALS':{'value':'o'}
,'EQUALS':{'value':'e'}
,'RANGE_EXCLUSIVE':{'value':'E'}
,'RANGE_INCL_RIGHT':{'value':'R'}
,'NOT_CONTAIN':{'value':'k'}
,'RANGE_INCL_LEFT':{'value':'L'}
,'LIKE':{'value':'i'}
}
;
/*
* @author mpolcari
* @since 142.wm
*/

function GenericSfdcPage() {
  this.init()

  this.inlineHelpMap = {};
  this.helpFader = null;
  this.helpParentElement = null;

  var self = this;

  this.handleHelpHover = function(e){
      var target = getEventTarget(getEvent(e));
      if (!target || UserContext.isAccessibleMode) return;
      if (target.className == InlineHelp.CLASS_NAME){
          target.className = InlineHelp.CLASS_NAME_HOVER;
      } else if (target.nodeName == 'LABEL' && target.parentNode && target.parentNode.className == InlineHelp.CLASS_NAME){
          target.parentNode.className = InlineHelp.CLASS_NAME_HOVER;
      }else if (target.className == InlineHelp.ORB){
          helpSpan = target.parentNode;
          while (!(helpSpan.className == InlineHelp.CLASS_NAME || helpSpan.className == InlineHelp.CLASS_NAME_HOVER)){
              helpSpan = helpSpan.parentNode
          }
          var helpId = helpSpan.id;
          helpSpan.className = InlineHelp.CLASS_NAME_HOVER;
          if (helpId && helpId.length > InlineHelp.ID_SUFFIX.length){
              var helpKey = helpId.substring(0, helpId.length - InlineHelp.ID_SUFFIX.length);
              self.showHelp(helpKey, helpSpan);
          }
      }
  }

  this.handleHelpUnhover = function(e){
      var target = getEventTarget(getEvent(e));
      if (!target || UserContext.isAccessibleMode) return;
      if ((target.className == InlineHelp.CLASS_NAME_HOVER) && mouseExited(e, target)){
          target.className = InlineHelp.CLASS_NAME;
      } else if ((target.nodeName == 'LABEL' && target.parentNode.className == InlineHelp.CLASS_NAME_HOVER) && mouseExited(e, target.parentNode)) {
          target.parentNode.className = InlineHelp.CLASS_NAME;
      } else if (target.className == InlineHelp.DISPLAY_DIV_CLASS && mouseExited(e, target)){
          var toElement = getEventToElement(getEvent(e));
          if (toElement && toElement.className != InlineHelp.ORB && self.helpFader){
              self.helpFader.fadeOut();
          }
      } else if (target.className == InlineHelp.ORB && mouseExited(e, target)){
          var toElement = getEventToElement(getEvent(e));
          var parent = target.parentNode;
          //hack for accessiblity mode, where the img has a link around it.
          if (UserContext.isAccessibleMode){
              parent = parent.parentNode;
          }
          if (toElement.className == InlineHelp.DISPLAY_DIV_CLASS){
              return;
          }
          if (toElement != parent){
              parent.className = InlineHelp.CLASS_NAME;
          }
          if (self.helpFader){
              self.helpFader.fadeOut();
          }
      }
  }

  this.appendToOnloadQueue(function() {
      addEvent(document, 'mouseover', self.handleHelpHover, false);
        addEvent(document, 'mouseout', self.handleHelpUnhover, false);
        if (XBrowser.userAgent.isIE){
            addEvent(document.body, 'click', self.handleLabelClickIEOnly);
        }
  });
}

GenericSfdcPage.prototype.init = function() {
  this.onLoadQueue = [];
  this.onBeforeUnloadQueue = [];
  this.hasRun = false;
  this.relatedLists = [];
  this.relatedListsById = {};
  this.dialogs = {};
  this.messages = {};
  this.appendToOnloadQueue(function() { XBrowser.turnOnBackgroundImageCache(); }, "Turn on CSS background image cache (IE6 only)");
}

GenericSfdcPage.prototype.handleLabelClickIEOnly = function(e){
    var event = getEvent(e);
    var target = getEventTarget(event);
    if (!target) return;
    if (target.tagName == "LABEL" && target.htmlFor){
        var input = getElementByIdCS(target.htmlFor);
        if (input){
        	if (input.type && input.type.toLowerCase() == 'checkbox'){
        		input.click()
        	} 
        	if (input.focus){
        		input.focus();
        		e.returnValue = false;
        	}
        }
    }
};

GenericSfdcPage.prototype.prependToOnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  if (this.hasRun) {
    this.execFunctionNoThrow(fn); //if the queue has already run, just execute this function
  } else {
    this.onLoadQueue.unshift(fn);
  }
}

GenericSfdcPage.prototype.appendToOnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  if (this.hasRun) {
    this.execFunctionNoThrow(fn); //if the queue has already run, just execute this function
  } else {
    this.onLoadQueue.push(fn);
  }
}

GenericSfdcPage.prototype.executeOnloadQueue = function() {
  for(var i = 0; (this.onLoadQueue && (i < this.onLoadQueue.length)); i++) {
    this.execFunctionNoThrow(this.onLoadQueue[i]);
  }
  this.hasRun = true;
  this.onLoadQueue = [];
}

GenericSfdcPage.prototype.prependToOnBeforeUnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  this.onBeforeUnloadQueue.unshift(fn);
}

GenericSfdcPage.prototype.appendToOnBeforeUnloadQueue = function(fn, description) {
  if (description) fn.desc = description;
  this.onBeforeUnloadQueue.push(fn);
}

GenericSfdcPage.prototype.executeOnBeforeUnloadQueue = function() {
  for(var i = 0; (this.onBeforeUnloadQueue && (i < this.onBeforeUnloadQueue.length)); i++) {
    this.execFunctionNoThrow(this.onBeforeUnloadQueue[i]);
  }
}

GenericSfdcPage.prototype.execFunctionNoThrow = function(fn) {
    try {
      fn();
    } catch (ex) {
      if (fn.desc) ex.sfdcDesc = fn.desc;
      Gack.handleException(ex);
    }
}


GenericSfdcPage.prototype.registerRelatedList = function(listId, visibleRowCount, title, hasMore, refURL, refQS, onlySkipLink) {
  var firstList = (this.relatedLists.length == 0);

  if(!this.relatedListsById[listId]){
      this.relatedListsById[listId] = new RelatedList(listId, visibleRowCount, title, hasMore, refURL, refQS, onlySkipLink);
      this.relatedLists.push(this.relatedListsById[listId]);
  }

  if (this.relatedListPanel) {
    this.relatedListPanel.registerList(this.relatedListsById[listId]);
  }
  ///If this is the first RL on the page, queue up the panel initialization script
   var self = this;
   if (firstList) {
     this.prependToOnloadQueue(
       function () {
         if ((self.relatedListPanel) && (self.relatedListPanel.addListsToPanel)) {
           self.relatedListPanel.addListsToPanel();
         }
      }, "rlHovers: Initializing panel");
    }
}

GenericSfdcPage.prototype.registerDialog = function(dialog) {
    this.appendToOnloadQueue(function() { dialog.createDialog(); }, "Create a dialog");
    this.dialogs[dialog.id] = dialog;
}

GenericSfdcPage.prototype.getDialogById = function(dialogId) {
    return this.dialogs[dialogId];
}

GenericSfdcPage.prototype.getRelatedListById = function(listId) {
  return this.relatedListsById[listId];
}

/**
  Retrieves the current address as an URLencoded retUrl
*/
GenericSfdcPage.prototype.getHrefAsRetURL = function() {
  var href = window.location.href;

  var retUrlArr = href.split("/");
  retUrlArr.splice(0,3);
  return encodeURIComponent("/" + retUrlArr.join("/"));
}

GenericSfdcPage.prototype.includeJavascriptTag = function(scriptUri) {
    return this.embedJSTag(scriptUri, document);
}

GenericSfdcPage.prototype.embedJSTag = function(scriptUri, doc) {
    var html_doc = doc.getElementsByTagName('head').item(0);
    var js = doc.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', scriptUri);
    html_doc.appendChild(js);
    return false;
}

GenericSfdcPage.prototype.embedExternalStyleSheet = function(sheetUrl, doc) {
    var styleNode = doc.createElement("link");
    styleNode.setAttribute("href", sheetUrl);
    styleNode.setAttribute("type", "text/css");
    styleNode.setAttribute("rel", "stylesheet");

    var targetHead = doc.body.parentNode.firstChild;
    targetHead.appendChild(styleNode);
}

GenericSfdcPage.prototype.hideEmbeddingIframe = function(iframeWin) {
    if (iframeWin.name && document.getElementById(iframeWin.name)) {
      document.getElementById(iframeWin.name).style.display = 'none';
      document.getElementById(iframeWin.name).parentNode.style.border ='none';
    }
}

GenericSfdcPage.prototype.setHelp = function(key, text){
    this.inlineHelpMap[key] = text;
}

GenericSfdcPage.prototype.getHelp = function(key){
    return this.inlineHelpMap[key];
}

/**
 * Set parent for the help element
 */
GenericSfdcPage.prototype.setHelpParent = function(parentElement){
    this.helpParentElement = parentElement;
}

GenericSfdcPage.prototype.showHelp = function(id, element){
    var help = this.getHelp(id);
    if (help){
        if (!this.displayDiv){
            this.displayDiv = document.createElement("DIV");
            this.displayDiv.className = InlineHelp.DISPLAY_DIV_CLASS;
        }

        // set the local variable of parentElement to be class level this.helpParentElement
        var parentElement = this.helpParentElement;

        // if this.helpParentElement is not set, get the default value
         if (!parentElement) {
            var parentElement = document.getElementById(BodyLayout.BODY_CELL_ID);
            if (!parentElement){
                parentElement = document.body;
            }
         }

        parentElement.appendChild(this.displayDiv);
        this.displayDiv.style.top = (getObjY(element) + element.offsetHeight + 8 - getObjY(parentElement)) + 'px';
        if (!this.helpFader){
            this.helpFader = new MouseOverFadeHandler(null, this.displayDiv, false);
        }
        this.displayDiv.innerHTML = help;
        this.helpFader.setPosition();

        // calculate the left based on the parement element's left value
        var left = (getObjX(element) - getObjX(parentElement) + element.offsetWidth - this.displayDiv.offsetWidth);
        //Make sure it's not behind the sidebar.
        var sidebar = document.getElementById(SidebarConstants.SIDEBAR_DIV_ID);
        if (sidebar){
            var sidebarRight = getObjX(sidebar) + sidebar.offsetWidth;
            if (left < sidebarRight){
                left = sidebarRight;
            }
        }
        if (left >= 0){
            this.displayDiv.style.left = left + 'px';
        }
        this.helpFader.fadeIn();
    }
}

/**
 * simple messaging for now. should have type, strength, etc and allow sorting, dismissing...
 */
GenericSfdcPage.prototype.registerMessage = function(id) {
    var message = document.getElementById(id);
    if (message && !this.messages[id]) {
        this.messages[id] = message;
    }
}

GenericSfdcPage.prototype.hideMessage = function(id) {
    var message = this.messages[id];
    if (message) {
        message.style.display = "none";
    }
}

GenericSfdcPage.prototype.showMessage = function(id) {
    var message = this.messages[id];
    if (message) {
        message.style.display = "block";
    }
}

// used for search similar utility button. constructs target url
GenericSfdcPage.prototype.findSimilarNavigate = function(tagName1, titleId, descriptionId, custFieldId){
    var tagTypeElements = document.getElementsByTagName(tagName1);
    var custInputs = document.getElementById(custFieldId);
    var descriptionElement = document.getElementById(descriptionId);
    var titleElement = document.getElementById(titleId);
    var qs = new QueryString("");
    var searchCommand ="common.search.similar.IdeaFindSimilarProvider";
    var url = UserContext.getUrl("/_ui/common/search/similar/FindSimilarQueryPage/d");
    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, titleElement.innerHTML," "); // manually add default fields, diff depth than custom fields
    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, descriptionElement.innerHTML," ");

    function appendSearchStringComponents (tagTypeElements, customFieldContainerId){
        for(var i =0; i < tagTypeElements.length; i++){
            var node = tagTypeElements[i];
            var shouldConitnue = false;
            for(var j = 0; j < 6; j++){
                    node = node.parentNode;
                    if(!node){
                        shouldConitnue = true;
                        break;
                    }
                }
            if(shouldConitnue || !node.id){
                    continue;
            }
            var id = node.id;
            if(id == customFieldContainerId){
                    qs.append(findSimilarQueryPage.SEARCH_QUERY_STRING, tagTypeElements[i].innerHTML, " ");
            }
        }
    }
    if(custInputs!=undefined){
        appendSearchStringComponents(tagTypeElements, custInputs.id);
       }
    qs.add(findSimilarQueryPage.FIND_PROVIDER, searchCommand);
    return url + qs.toString();
}



/**
 * Introducing a brand new flavor of UserContext, this time in javascript! Variables passed down from
 * java MUST be declared here or they will not be set.
 * 
 * @author jmooney
 * @since 148
 */
var UserContext = {
	
    initialized : false,
    locale : "",
    language: "",
    startOfWeek : 0,
    dateFormat : "",
    dateTimeFormat : "",
    ampm: null,
    today : "",
    isAccessibleMode : false,
    userPreferences : null,
    siteUrlPrefix : "",

    initialize : function(values) {
    	if (!values){
    		UserContext.initializeFromServlet();
    		return;
    	}
    	UserContext.processValues(values);
    },
    
    initializeFromServlet : function(){
		var url = UserContext.getUrl("/_ui/system/context/UserContextServlet");
		XBrowser.getHttpResponse(url, function(request) {
		    var values = Util.evalAjaxServletOutput(request.responseText);
    	    UserContext.processValues(values);
		} );
    },
    
    processValues : function (values) {
        for (var key in values) {
            // force strict variable declaration
            if (typeof UserContext[key] != "undefined") {
                if (key == "userPreferences" || key == "orgPreferences") {
                    UserContext[key] = new PreferenceBits(values[key]);
                } else {
                    UserContext[key] = values[key];
                }
            }
        }
        UserContext.initialized = true;
    },

    getUrl : function (url) {
        // fix URL for sites with prefixes
        if (typeof url == "undefined" || typeof UserContext.siteUrlPrefix == "undefined" || !UserContext.siteUrlPrefix) 
            return url;

        if (url.indexOf('/') != 0)
            return url;

        if(url.indexOf(UserContext.siteUrlPrefix) == 0)
            return url;

        return UserContext.siteUrlPrefix + url;
    }
    
};

function CustomSummaryFieldAttributes(servletUrl, parentEntityEnumOrId, entityId, fieldTargetId, radioName, oppLabels, numFilters, initialMap){
	this.radios = document.getElementsByName(radioName);
	this.parentEntityEnumOrId = parentEntityEnumOrId;
	this.servletUrl = servletUrl;
	this.entityElement = document.getElementById(entityId);
	this.fieldTarget = document.getElementById(fieldTargetId);
	if (this.entityElement){
		this.currentEntity = this.getEntityValue(this.entityElement.options[this.entityElement.selectedIndex].value);
	} else {
		//Invariant:  entityElement exists, or initialMap exists and has exactly one key
		for (var entityName in initialMap){
  			//Get the first key, should only be one
			this.currentEntity = entityName;
			break;
		}
	}
	
	this.oldOpVal = null;
	for (var i = 0; i < this.radios.length; i++){
		if (this.radios[i].checked){
			this.oldOpVal = this.radios[i].value;
			break;
		}
	}
	if (initialMap){
		this.cache = initialMap;
	} else {
		this.cache = {};
	}
	this.criteriaCache = {};
		
	var self = this;
	
	this.handleRadioClick = function(e){
		var newOpVal;
		for (var i = 0; i < self.radios.length; i++){
			if (self.radios[i].checked){
				newOpVal = self.radios[i].value;
				break;
			}
		}
		if (CustomSummaryFieldAttributes.getShownFields(newOpVal) != CustomSummaryFieldAttributes.getShownFields(self.oldOpVal)){
			self.setCurrentEntity();
		}
		self.oldOpVal = newOpVal;
	}
	
	this.handleEntityChange = function(e){
		var entityElementValue = self.getEntityValue(self.entityElement.options[self.entityElement.selectedIndex].value);
		self.setCurrentEntity(entityElementValue);	
	}
	
	this.handleFilterViewClick = function(e){
		var radio = getEventTarget(getEvent(e));
		document.getElementById(CriteriaInputConstants.FILTER_SECTION_ID).style.display = (radio.value == "1" ? "block" : "none");
	}
	
	this.cacheFieldsFromResponse = function(request){
		var response = Util.evalAjaxServletOutput(request.responseText);
		var fields = response[AjaxLoadFieldsForEntity.pFIELD_LIST];
		self.cache[response[AjaxLoadFieldsForEntity.pENTITY_NAME]] = fields;
		self.fillFieldsFromCache();
	}
	
	/**
	 * This can be called with no arguments to refresh the list based on this.currentEntity
	 */
	this.setCurrentEntity = function(value){
		if (typeof(value) != "undefined"){
			self.currentEntity = value;
		}
		if (self.currentEntity){
			self.setOpsEnabled(true);
			var fields = self.cache[self.currentEntity];
			if (fields){
				self.fillFieldsFromCache();
			} else {
				var	postMap = {};
				postMap[self.entityElement.name] = self.currentEntity;
				postMap[AjaxLoadFieldsForEntity.pPARENT_ENTITY_NAME] = self.parentEntityEnumOrId;
				XBrowser.postHttpResponse(self.servletUrl, self.cacheFieldsFromResponse, XBrowser.buildPost(postMap));
			}
		} else {
			self.setOpsEnabled(false);
		}
	}
	
	this.setOpsEnabled = function(enabled){
		if (self.radios && self.radios.length > 0){
			//will be empty if field is managed-installed or managed-released
			for (var i = 0; i < self.radios.length; i++){
				self.radios[i].disabled = !enabled;
				if (!enabled){
					self.radios[i].checked = false;
				}
			}
		}
		if (self.fieldTarget){
			self.fieldTarget.disabled = !enabled;
			if (!enabled){	
				self.fieldTarget = Util.refreshDynamicSelect(self.fieldTarget, [], true);
				self.fieldTarget.disabled = true;
			}
		}
	}
	
	var prevCriteriaData;
	if (this.currentEntity){
		prevCriteriaData = new CriteriaEntityData(this.currentEntity, this.cache[this.currentEntity]);
		this.criteriaCache[this.currentEntity] = prevCriteriaData;
	}
	this.criteriaInput = new CriteriaInput(oppLabels, numFilters, prevCriteriaData);
	
	if 	(this.currentEntity){
		this.setCurrentEntity();
	} else {
		this.setOpsEnabled(false);
	}

	this.initEvents();		
}

CustomSummaryFieldAttributes.prototype.getEntityValue = function(picklistVal){
	if (!picklistVal){
		return null;
	}
	return picklistVal.substring(0, picklistVal.indexOf('.'));
}

CustomSummaryFieldAttributes.prototype.showOptions = function(shown){
	document.getElementById(SummaryFieldConstants.OPTIONS_ID).style.display = shown ? 'block' : 'none';
}

CustomSummaryFieldAttributes.prototype.initEvents = function(){
	for (var i = 0; i < this.radios.length; i++){
		addEvent(this.radios[i], 'click', this.handleRadioClick, false);
	}
	var filterViewRadios = document.getElementsByName(CriteriaInputConstants.SHOW_SUMMARY_FILTER);
	for (var i = 0; i < filterViewRadios.length; i++){
		addEvent(filterViewRadios[i], 'click', this.handleFilterViewClick, false);
		if (filterViewRadios[i].value == "1" && filterViewRadios[i].checked){
			document.getElementById(CriteriaInputConstants.FILTER_SECTION_ID).style.display = "block";
		}
	}
	if (this.entityElement){
		addEvent(this.entityElement, 'change', this.handleEntityChange, false);
	}
}

CustomSummaryFieldAttributes.prototype.setCurrentCriteria = function(entity){
	var fields = this.cache[entity];
	if (!fields){
		Gack.sendGack("criteriadata set before fields loaded.  Entity: " + entity);
	}	
	var criteriaEntity = this.criteriaCache[entity];
	if (!criteriaEntity){
		criteriaEntity = new CriteriaEntityData(entity, fields);
		this.criteriaCache[entity] = criteriaEntity;
	}
	this.criteriaInput.setEntity(criteriaEntity);
}

CustomSummaryFieldAttributes.prototype.fillFieldsFromCache = function(){
	var shownFields;	
	for (var i = 0; i < this.radios.length; i++){
		if (this.radios[i].checked){
			shownFields = CustomSummaryFieldAttributes.getShownFields(this.radios[i].value);
			break;
		}
	}
	
	this.setCurrentCriteria(this.currentEntity);
	
	var anyOptions = false;
	var prevOptionIndex = 0;
	if (this.fieldTarget){
		if(!shownFields){
			this.fieldTarget = Util.refreshDynamicSelect(this.fieldTarget, [], true, "")
		} else {
			var prevOption;
			if (this.fieldTarget.options && this.fieldTarget.selectedIndex >= 0){
				//Options already exist, see if one is selected and hold on to it
				prevOption = this.fieldTarget.options[this.fieldTarget.selectedIndex].value;
			}
			
			var options = []
			var fields = this.cache[this.currentEntity];
			var numShownOptions = 1;
			for (var i = 0; i < fields.length; i++){
				if (fields[i].columnType in shownFields){
					anyOptions = true;
					options.push([fields[i].label, fields[i].name]);
					numShownOptions++;
				}
			}
			this.fieldTarget = Util.refreshDynamicSelect(this.fieldTarget, options, true, prevOption);
		}
	
		if (!anyOptions){
			this.fieldTarget.disabled = true;
		} else {
			this.fieldTarget.disabled = false;
		}
	}
}

CustomSummaryFieldAttributes.getShownFields = function(enumVal) {
	switch (enumVal){
		case "0":
			return null;
		case "1":
			var ar = {};
			for (var type in ColumnType){
				if (ColumnType[type].isNumber){
					ar[type] = true; 
				}
			}
			return ar;
		case "2":
		case "3":
			var ar = {};
			for (var type in ColumnType){
				if (ColumnType[type].isNumber || ColumnType[type].isDate){
					ar[type] = true; 
				}
			}
			return ar;
	}
}


function ImageSelectElement (hiddenElementId, imageId, partialImgURL) {
 var self = this;
 this.inputElement = document.getElementById(hiddenElementId);
 this.image = document.getElementById(imageId);
 this.partialImageURL = partialImgURL;  //org-specific

//hook this onto the hidden input box, as that's the main id for ImageInputElements
 this.inputElement.imageSelectElement = this;

 this.inputElement.onchange =
 function() {
  //this should set the visible image
  self.image.src = self.partialImageURL + self.inputElement.value;
  }
}

ImageSelectElement.prototype.isNull = function() {
  return (!((this.inputElement) && (this.inputElement.value) && (this.inputElement.value.length > 0)));
}


/**
 * Holds data about fields on a detail page for inline editing.
 * 
 * @author jmooney
 * @since 150
 */
function InlineEditData(json) {
    this.isEditable = json[InlineEditConstants.EDITABLE];
    this.sysMod = json[InlineEditConstants.LAST_MOD];
    this.id = json[InlineEditConstants.ENTITY_ID];
    this.csrf_token = json[CSRFConstants.CSRF_TOKEN];
    this.fields = {};
    this.dependencyGroups = [];
    this.hasCompoundFields = false;
    this.allFieldData = json[InlineEditConstants.FIELD_DATA];
    this.dynamicDataUrl = json[InlineEditConstants.DYNAMIC_DATA];
    this.loadedDynamicData = false;
    this.sentRequest = false;
    this.currentField = null;
    sfdcPage.initInlineEdit(this);
}

InlineEditData.prototype.init = function() {
    this.createFields();
    if (this.hasCompoundFields) {
        InlineEditField.overlay = new InlineEditDialog();
        InlineEditField.overlay.register();
    }
    var self = this;
    addEvent(document, "click", function() { self.closeCurrentField(); }, false);
}

InlineEditData.prototype.createFields = function() {
    if (this.allFieldData) {
        for (var i = 0; i < this.allFieldData.length; i++) {
            var fieldData = this.allFieldData[i];
            var field = InlineEditField.createField(fieldData);
            this.fields[fieldData.fieldId] = field;
            if (field) {
                if (field.compound) {
                    this.hasCompoundFields = true;
                }
            }
        }
        // create dependencies after all fields are loaded
        for (var i in this.fields) {
            var f = this.fields[i];
            if (f && f.controllerId) {
                this.createDependency(f);
                this.hasCompoundFields = true;
            }
        }
    }
}

InlineEditData.prototype.createDependency = function(field) {
    if (field.group) {
        // already in a group, nothing to do
        return;
    }
    // try to find existing group of a controller, and add to that group
    var f = this.getField(field.controllerId);
    var existingGroup = null;
    while (f != null) {
        existingGroup = f.group;
        if (existingGroup) {
            break;
        }
        f = this.getField(f.controllerId);
    }
    if (existingGroup) {
        // found a group, add fields until we get back to f
        var temp = field;
        var start = existingGroup.length;
        while (temp != f) {
            existingGroup.splice(start, 0, temp.id);
            temp.group = existingGroup;
            if (temp instanceof BooleanField) {
                // tell boolean fields to wait for the rest of the dependency to load
                temp.waitForLoad = true;
            }
            temp = this.getField(temp.controllerId);
        }
    } else {
        // have to create a new group
        var newGroup = [];
        var temp = field;
        while (temp != null) {
            newGroup.unshift(temp.id);
            temp.group = newGroup;
            if (temp instanceof BooleanField) {
                // tell boolean fields to wait for the rest of the dependency to load
                temp.waitForLoad = true;
            }
            temp = this.getField(temp.controllerId);
        }
        this.dependencyGroups.push(newGroup);
    }
}

InlineEditData.prototype.openField = function(field) {
    if (field.group) {
        field = this.fields[field.group[0]];
    } else if (!this.isCurrentField(field)) {
        this.closeCurrentField();
    }
    this.currentField = field;
    if (field.waitForLoad && !this.loadedDynamicData) {
        this.loadDynamicData();
        return;
    } else if (field.group) {
        this.openGroup(field.group);
    } else {
        field.openField();
    }
}

InlineEditData.prototype.openGroup = function(group) {
    var first = this.fields[group[0]];
    if (!first.created) {
        var div = document.createElement("div");
        div.className = "inlineEditDiv";
        document.body.appendChild(div);
        // create a table for the edit elements in the group
        var html = [];
        html.push("<table border=0>");
        for (var i = 0; i < group.length; i++) {
            var f = this.fields[group[i]];
            html.push("<tr><td class='labelCol'>");
            html.push(f.getFieldLabel());
            html.push("</td><td></td></tr>");
            if (f.state == InlineEditState.EDIT) {
                f.createEditDiv();
            } else {
                f.createDummy();
            }
        }
        html.push("</table>");
        div.innerHTML = html.join('');
        // after creating all select elements we can load the dependencies and insert into the table
        for (var i = 0; i < group.length; i++) {
            var f = this.fields[group[i]];
            var node;
            if (f.state == InlineEditState.EDIT) {
                f.load();
                div.firstChild.rows[i].lastChild.appendChild(f.editDiv);
            } else {
                div.firstChild.rows[i].lastChild.innerHTML = f.initialHTML;
            }
        }
        InlineEditField.overlay.addField(first.id, div, LC.getLabel("DependentElement", "dependentFields"));
    }
    InlineEditField.overlay.setActiveField(first.id);
    InlineEditField.overlay.setMaxWidth(400);
    InlineEditField.overlay.show();
}

InlineEditData.prototype.isCurrentField = function(field) {
    return this.currentField && this.currentField == field && !this.currentField.group;
}

InlineEditData.prototype.closeCurrentField = function() {
    if (this.currentField) {
        if (this.currentField.group) {
            this.closeGroup(this.currentField.group);
            this.currentField = null;
        } else {
            this.currentField.closeField();
            this.currentField = null;
        }
    }
}

InlineEditData.prototype.closeGroup = function(group) {
    for (var i = 0; i < group.length; i++) {
        var f = this.fields[group[i]];
        if (f.state == InlineEditState.EDIT) {
            var newValue = f.getValueFromEdit();
            if (f.isDifferentValue(newValue)) {
                if (!f.changed) {
                    f.changed = true;
                    addStyleClass(f.readDiv, "inlineEditModified");
                }
                f.currentValue = newValue;
                f.updateReadElement();
                if (f.changed) {
                    f.readDiv.appendChild(f.undoButton);
                    f.undoButton.style.display = "inline";
                }
            } else if (f.changed) {
                f.changed = false;
                f.currentValue = newValue;
                delStyleClass(f.readDiv, "inlineEditModified");
                f.updateReadElement();
                f.undoButton.style.display = "none";
            }
        }
    }
    InlineEditField.overlay.hide();
}

InlineEditData.prototype.resetCurrentField = function() {
    this.resetField(this.currentField);
    this.currentField = null;
}

InlineEditData.prototype.resetFieldById = function(id) {
    this.resetField(this.fields[id]);
}

InlineEditData.prototype.resetField = function(field) {
    if (field) {
        if (field.group) {
            this.resetGroup(field.group);
        } else {
            field.reset();
        }
    }
}

InlineEditData.prototype.resetGroup = function(group) {
    for (var i = 0; i < group.length; i++) {
        var f = this.fields[group[i]];
        if (f.state == InlineEditState.EDIT) {
            f.reset();
        }
    }
    InlineEditField.overlay.hide();
}

InlineEditData.prototype.getField = function(id) {
    if (id) {
        return this.fields[id];
    }
    return null;
}

InlineEditData.prototype.save = function() {
    if (this.isEditable) {
        this.closeCurrentField();
        var saveData = {};
        saveData[InlineEditConstants.ENTITY_ID] = this.id;
        saveData[InlineEditConstants.LAST_MOD] = this.sysMod;
        saveData[CSRFConstants.CSRF_TOKEN] = this.csrf_token;
        saveData[EditPageConstants.pSAVE] = "1"
        for (var id in this.fields) {
            var field = this.fields[id];
            // don't post data from read only fields, but do post from none fields because they are usually editable
            if (field && field.doPost()) {
                field.clearError();
                field.addSaveData(saveData);
            }
        }
        var self = this;
        XBrowser.postHttpResponse(UserContext.getUrl("/ui/common/InlineEditEntitySave"),
                                  function(response) { self.handleResponse(response.responseText); },
                                  XBrowser.buildPost(saveData),
                                  // check the errorMsg??
                                  function(response) {
                                      var url = escape(window.location.pathname+window.location.search);
                                      window.location.replace(UserContext.getUrl("/ex/errorduringprocessing.jsp?retURL=") + url);
                                  }
                                  );
    }
}

InlineEditData.prototype.handleResponse = function(responseText) {
    var response = Util.evalAjaxServletOutput(responseText);
    if (response[InlineEditConstants.SUCCESS]) {
        sfdcPage.refreshDetail();
    } else {
    	this.csrf_token = response[CSRFConstants.CSRF_TOKEN];
        this.handleErrors(response);
    }
}

InlineEditData.prototype.handleErrors = function(response) {
    sfdcPage.setError(response[InlineEditConstants.NON_SPECIFIC_ERRORS]);
    var specific = response[InlineEditConstants.VALIDATION_ERRORS];
    var first;
    for (var id in specific) {
        var f = this.getField(id);
        // error could be on a field that isn't on the page if somebody changed metadata after page 
        if (f) {
            // try to find the first simple field with an error and open it
            if (!f.overlay && !f.group) {
                // all fields have same offsetParent so use local y coord
                if (!first || first.tableCell.offsetTop > f.tableCell.offsetTop) {
                    first = f;
                }
            }
            f.setError(specific[id]);
        }
    }
    if (first) {
        this.openField(first);
    }
}

InlineEditData.prototype.revert = function() {
    if (this.isEditable) {
        this.closeCurrentField();
        var resetGroups = {};
        for (var id in this.fields) {
            var field = this.fields[id];
            if (field) {
                if (field.changed) {
                    // groups need to be reset separately
                    if (field.group) {
                        resetGroups[field.group[0]] = true;
                    } else {
                        field.reset();
                    }
                } else {
                    field.clearError();
                }
            }
        }
        for (var id in resetGroups) {
            this.resetGroup(this.fields[id].group);
        }
    }
}

InlineEditData.prototype.loadDynamicData = function() {
    if (!this.sentRequest) {
        this.sentRequest = true;
        var self = this;
        XBrowser.createDynamicScript(this.dynamicDataUrl, function() { self.dynamicDataLoaded(); });
    }
}

InlineEditData.prototype.dynamicDataLoaded = function() {
    if (!this.loadedDynamicData) {
        this.loadedDynamicData = true;
        if (this.currentField.waitForLoad) {
            this.openField(this.currentField);
        }
    }
}


function ApiUtils() {}

ApiUtils.getApiURL = function(isPartner, version) {
    var url = window.location.href;
    var idx = url.indexOf('/', 10); // well after (http|https)://
    var base = url.substring(0, idx) + UserContext.getUrl("/services/Soap/") + (isPartner ? "u" : "c") + "/" + version;
    return base;
}

ApiUtils.getSessionId = function(){
    var sessionId = getCookie(RequestInfo.pSID);
    return sessionId;
}

// fluff up a 15 char id to return an 18 char id
ApiUtils.to18CharId = function (id) {
 if (id == null || (id.length == 18)) return id;
 id = id.replace(/\"/g, ''); // scrub quotes from this id
 if (id.length != 15) {
  return null;
 }
 var suffix = "";
 for (var i = 0; i < 3; i++) {
  var flags = 0;
  for (var j = 0; j < 5; j++) {
   var c = id.charAt(i * 5 + j);
   if (c >= 'A' && c <= 'Z') {
    flags += 1 << j;
   }
  }
  if (flags <= 25) {
   suffix += "ABCDEFGHIJKLMNOPQRSTUVWXYZ".charAt(flags);
  } else {
   suffix += "012345".charAt(flags-26);
  }
 }
 return id + suffix;
}

ApiUtils.to15CharId = function(id){
    if (!id) return null;
    return id.substring(0, 15);
}

// the id field returned by the API is often returned twice,resulting
// in an array when calling record.get(). this returns a single ID always.
ApiUtils.getId = function(record){
    if (!record) return null;
    var id = record.get("Id");
    // looking for array by checking for "splice()" function
    if (id.splice && id.length && id.length > 0) {
        id = id[0];
    }
    if (id){
        id = ApiUtils.to15CharId(id);
    }
    return id;
}

ApiUtils.soqlEncode = function(str){
    var newStr = str;
    newStr = newStr.replace("\\", "\\\\");
    newStr = newStr.replace("'", "\\'");
    return newStr;
}

function SchedulePageUtil() {}

SchedulePageUtil.clickExpand = function() {
	Animation.rollIn(document.getElementById(SchedulePage.pDuelOuter), function() {});
}

SchedulePageUtil.clickCollapse = function() {
	Animation.rollOut(document.getElementById(SchedulePage.pDuelOuter), function() {});
}

SchedulePageUtil.disableTime = function(suffix) {
	document.getElementById(ScheduleElement.pPrefTime + suffix).value = '';
	document.getElementById(ScheduleElement.pPrefTime + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pPrefTime + suffix).disabled = true;

	document.getElementById(ScheduleElement.pOtherPrefTimeLabelDiv + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'block';
}

SchedulePageUtil.enableTime = function(suffix) {
	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'none';
	document.getElementById(ScheduleElement.pOtherPrefTimeLabelDiv + suffix).style.display = 'none';

	//start loading
	document.getElementById(ScheduleElement.pPrefTimeLoadingDiv + suffix).style.display = 'block';

	var saveData = SchedulePageUtil.buildPost(suffix);
	XBrowser.postHttpResponse(UserContext.getUrl(BlowoutServlet.SERVLETURL),
                                  function(response) { SchedulePageUtil.handleResponse(suffix, response.responseText); },
                                  XBrowser.buildPost(saveData),
                                  // check the errorMsg??
                                  null
                                  );
	return false;
}

SchedulePageUtil.buildPost = function(suffix) {
	var saveData = {};
	saveData[BlowoutServlet.SUFFIX] = suffix;

	saveData[SchedulePage.pBlowout] = document.getElementById(SchedulePage.pBlowout).value;
	saveData[SchedulePage.pIsOffPeak] = document.getElementById(SchedulePage.pIsOffPeak).value;
	saveData[ScheduleElement.pFreq + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pFreq + suffix);
	saveData[ScheduleElement.pStartDate + suffix] = document.getElementById(ScheduleElement.pStartDate + suffix).value;
	saveData[ScheduleElement.pEndDate + suffix] = document.getElementById(ScheduleElement.pEndDate + suffix).value;
	saveData[ScheduleElement.pDailyRec + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pDailyRec + suffix);
	//saveData[ScheduleElement.pDailyEveryNDays + suffix] = document.forms['editPage'].elements[ScheduleElement.pDailyEveryNDays + suffix].value;

	for (var i = 0; i < 7; i++) {
		saveData[ScheduleElement.pDayOfWeek + i + suffix] = document.getElementById(ScheduleElement.pDayOfWeek + i + suffix).checked ? '1' : '0';
	}

	saveData[ScheduleElement.pMonthlyRec + suffix] = SchedulePageUtil.getCheckedValue(ScheduleElement.pMonthlyRec + suffix);
	saveData[ScheduleElement.pMonthlyOnDayN + suffix] = document.getElementById(ScheduleElement.pMonthlyOnDayN + suffix).value;
	saveData[ScheduleElement.pMonthlyOnNthDay + suffix] = document.getElementById(ScheduleElement.pMonthlyOnNthDay + suffix).value;
	saveData[ScheduleElement.pMonthlyOnNDayOfWeek + suffix] = document.getElementById(ScheduleElement.pMonthlyOnNDayOfWeek + suffix).value;
    saveData[SchedulePage.pJobType] = document.getElementById(SchedulePage.pJobType).value;
    return saveData;
}

SchedulePageUtil.getCheckedValue = function(paramName) {
	var params = document.getElementsByName(paramName);

	if (params.length == null) {
		if (params.checked) return params.value;
	} else {
		for (var i = 0; i < params.length; i++) {
			if (params[i].checked) return params[i].value;
		}
	}
	return '';
}

SchedulePageUtil.handleResponse = function(suffix, responseText) {
    var response = null;
    try {
    	response = Util.evalAjaxServletOutput(responseText);
    } catch (err) {
		if (window.location.replace){
			window.location.replace(window.location);
		} else {
			window.location.href = window.location.href;
		}
    	return;
    }

    //stop loading
	document.getElementById(ScheduleElement.pPrefTimeLoadingDiv + suffix).style.display = 'none';

    if (response[BlowoutServlet.SUCCESS]) {
    	SchedulePageUtil.setTimePicklist(suffix, response[BlowoutServlet.BLOWOUT]);
    	document.getElementById(ScheduleElement.pPrefTime + suffix).disabled = false;
    	document.getElementById(ScheduleElement.pPrefTime + suffix).style.display = 'block';
    } else {
    	document.getElementById(ScheduleElement.pPrefTimeLabelDiv + suffix).style.display = 'block';
    }
    SchedulePageUtil.handleErrors(response);
}

SchedulePageUtil.setTimePicklist = function(suffix, values) {
	var options = document.getElementById(ScheduleElement.pPrefTime + suffix).options;

	//remove everything
	options.length = 0;

	if (values.length == 0) {
		options[0] = new Option(LC.getLabel('SelectElement', 'Required'), '');
	} else {
		for (var i = 0; i < values.length; i++) {
			options[i] = new Option(values[i], values[i]);
		}
	}
}

SchedulePageUtil.handleErrors = function(response) {
    var specific = response[AjaxServlet.ERROR_MSG_KEY];

    if (specific instanceof Array) {
    	if (specific.length > 3) {
    		document.getElementById(DetailElement.DEFAULT_ERROR_DIV_ID).style.display = 'block';
    	} else {
    		document.getElementById(DetailElement.DEFAULT_ERROR_DIV_ID).style.display = 'none';
    	}
	    for (var i = 0; i < specific.length; i++) {
	        var idAndVal = SchedulePageUtil.getIdAndVal(specific[i]);
	        SchedulePageUtil.setError(idAndVal[0], idAndVal[1]);
	    }
    } else {
    	//this is bad
    	//there are by default 3 elements in the array
    }
}

SchedulePageUtil.getIdAndVal = function(idVal) {
	return idVal.split(',');
}

SchedulePageUtil.setError = function(id, message) {
	//I have to get the div that this element is contained in.
	//Then search through that div and look for an errorMsg class
	//This is incrediby hacky and prone to error.
	var elem = null;
	if (document.getElementById(id).nodeName == "DIV") {
		elem = document.getElementById(id).parentNode
	} else {
		elem = document.getElementById(id).parentNode.parentNode;
	}
	var isErrorPresent = false;
	var errorLoc;
	for (var i = 0; i < elem.childNodes.length; i++) {
		if (elem.childNodes[i].className != null && elem.childNodes[i].className == "errorMsg") {
			isErrorPresent = true;
			errorLoc = i;
		}
	}

	//if the error is not there and we should be putting an error on the page, then create a new error div
    if (!isErrorPresent) {
    	if(message != '') {
	        var errorDiv = document.createElement("div");
		    errorDiv.className = "errorMsg";
		    errorDiv.innerHTML = message;
		    elem.appendChild(errorDiv);
    	}
    } else {
    	//if the error already exists on the page then simply show it
    	if(message != null) {
	        elem.childNodes[errorLoc].innerHTML = message;
	        elem.childNodes[errorLoc].style.display = "block";
    	} else {
    		elem.childNodes[errorLoc].style.display = "none";
    	}
    }
}



function ButtonInputElement() {}

ButtonInputElement.prototype.enableButton = function(name, enable) {
    var buttons = document.getElementsByName(name);
    if (buttons) {
        for (var i = 0; i < buttons.length; i++) {
            var button = buttons[i];

            button.disabled = !enable;
            button.className =enable ?  'btn' : 'btnDisabled';
        }
    }
}

/**
 * Lookup hover detail object.
 * @author jmooney
 * @since 148
 */
function LookupHoverDetail(id, url) {
    this.lookup = getElementByIdCS(id);
    this.width = 302;
    this.bubbleOffset = XBrowser.userAgent.isIE6 ? 5 : 14;
    this.height = 262;
    this.hover = document.createElement("div");
    this.hover.id = id + "Hover";
    this.hover.className = "individualPalette lookupHoverDetail";
    this.hover.innerHTML = "<div class=\"topLeft\">" + LC.getLabel("Global", "loading") + "</div>";
    document.body.appendChild(this.hover);
    var self = this;
    addEvent(this.hover, "mouseover", function() { self.show(); } , true);
    addEvent(this.hover, "mouseout", function() { self.hide(); }, true);
    this.hover = new iframeShim(this.hover);
    this.originalClass = "";
    this.fadingOut = null;
    this.fadingIn = null;
    this.loaderURL = url;
    this.loaded = false;
}

LookupHoverDetail.SHOW_DELAY = 800;
LookupHoverDetail.HIDE_DELAY = 250;
LookupHoverDetail.stopLoading = false;
// map from id to hover object
LookupHoverDetail.hovers = {};

// static function to retrieve a hover detail using a 15 char ID
LookupHoverDetail.getHover = function(id, url) {
    if (LookupHoverDetail.hovers[id]) {
        return LookupHoverDetail.hovers[id];
    }
    var hover = new LookupHoverDetail(id, url);
    LookupHoverDetail.hovers[id] = hover;
    return hover;
}

// show the hover detail
LookupHoverDetail.prototype.show = function() {
    if (this.fadingOut) {
        clearTimeout(this.fadingOut);
        this.fadingOut = null;
	} else {
        var self = this;
	    this.fadingIn = setTimeout( function() { self.showNow(); }, LookupHoverDetail.SHOW_DELAY);
    }
}

LookupHoverDetail.prototype.showNow = function() {
    if (!this.loaded) {
    	if (this.loaderURL != null) {
    		var self = this;
    		XBrowser.getHttpResponse(this.loaderURL, function(response) { self.load(response.responseText); }, function(response) { self.load(response.responseText); });
    	} else {
    		// we haven't loaded, and we have no URL to load from, so don't do anything.
    		return;
    	}
    }
    this.position();
    this.hover.setStyle("display", "block");
    this.fadingIn = null;
}

// hide the hover detail
LookupHoverDetail.prototype.hide = function() {
    if (this.fadingIn) {
        clearTimeout(this.fadingIn);
        this.fadingIn = null;
    } else {
        var self = this;
        this.fadingOut = setTimeout(function() { self.hideNow(); }, LookupHoverDetail.HIDE_DELAY);
    }
}

LookupHoverDetail.prototype.hideNow = function() {
    this.hover.setStyle("display", "none");
    this.fadingOut = null;
}

// loads the mini detail from the responseText
LookupHoverDetail.prototype.load = function(responseText) {
	this.hover.div.innerHTML = responseText;
	Util.evalScriptsUnderElement(this.hover.div);
	this.originalClass = this.hover.div.firstChild.className;
	this.position();
	this.loaded = true;
}

LookupHoverDetail.prototype.position = function() {
    var lookupX = getObjX(this.lookup);
    var lookupY = getObjY(this.lookup);
    var lookupW = this.lookup.offsetWidth;
    var lookupH = this.lookup.offsetHeight;
	var winX = getScrollX();
	var winY = getScrollY();
	var winWidth = getWindowWidth();
	var winHeight = getWindowHeight();
    var bubbleClass = this.originalClass + " ";
    var hoverX, hoverY;
    if (lookupY + lookupH + this.height < winY + winHeight) {
    	bubbleClass += "top";
    	hoverY = lookupY + lookupH;
    } else {
    	bubbleClass += "bottom";
    	hoverY = lookupY - this.height;
    }
    if (lookupX + lookupW - this.bubbleOffset + this.width < winX + winWidth) {
    	bubbleClass += "Left";
    	hoverX = lookupX + lookupW / 2 - this.bubbleOffset;
    } else {
    	bubbleClass += "Right";
    	hoverX = lookupX + lookupW / 2 - this.width; 
    }
    
    this.hover.setStyle("left", hoverX + "px");
    this.hover.setStyle("top", hoverY + "px");
    this.hover.div.firstChild.className = bubbleClass;;
}
/**
 * js object for enhanced list
 * @author jtroup, jmooney
 * @since 154
 */
function ListViewport(domId, type, payload, listId, customizable, rowsPerPage, height, width, draggable, vf) {
	this.domId = domId;
	this.listId = listId || domId;
	this.type = type;
	this.payload = payload;

	this.filter = null;
	this.inlineEditData = null;
	
	this.customizable = (typeof(customizable) == "undefined") ? true : customizable;
    this.rowsPerPage = rowsPerPage || null;
    this.height = height || null;
    this.width = width || null;
    this.draggable = draggable;
    this.vf = vf;
	
	this.wrapper = null;
	this.listViewport = null;
	this.topNav = null;
	this.filterLinks = null;
	this.rolodex = null;
	this.listBody = null;
	this.bottomNav = null;
	this.listSelect = null;
	this.pageState = null;
	this.rolodexState = null;
	this.exception = null;
	this.buttons = null;
	this.printLink = null;
	this.offPageIds = null;
	
	this.loading = null;
	this.saving = null;
	this.paginator = null;
	this.grid = null;
	this.linkTemplates = null;
	this.retURL = null;
	this.printURL = null;
		
	this.url = UserContext.getUrl("/_ui/common/list/ListServlet");
	this.xhr = null;
	
	this.rolodexIndex = null;
	var qs = new QueryString();
	this.trace = qs.get('trace');
	this.debug = qs.get('debug');

	ListViewport.addListViewport(this);
	
	var self = this;
	window.sfdcPage.appendToOnloadQueue(function() {self.init();});
	window.sfdcPage.appendToOnloadQueue(function() {self.redefineSidebarPin();});
    addEvent(window, "resize", function(){ self.resize();});
}

ListViewport.DEFAULT_COLUMN_WIDTH = 125;

ListViewport.prototype.resetTimer = function () {
	this.timepoint(null, true);
}

ListViewport.prototype.shrinkStore = function() {
	if (this.grid) {
		this.grid.getStore().filterBy(
			function(record, id) {return this.indexOf(record)==0}
		)
	}
}

ListViewport.prototype.unshrinkStore = function() {
	if (this.grid) {
		this.grid.getStore().clearFilter();
	}
}

ListViewport.prototype.sizeIfNoData = function() {
    if (this.grid.getStore().getTotalCount() == 0) {
        // size the empty data grid to the column header so you can scroll to see the columns (bug #173195)
		this.grid.getGridEl().query('.x-grid-empty')[0].style.width = this.grid.getColumnModel().getTotalWidth() + "px";
    }
}

ListViewport.prototype.timepoint = function (label, reset) {	
	if (!this.debug)
		return;

	if (!this.timer || reset) {
		this.timer = new Date();
		this.times = [];
	} else {
		var start = this.timer;
		this.timer = new Date();
		var elapsed = this.timer.getTime() - start.getTime();
		this.times.push({label: label, elapsed: elapsed});
	}
}

ListViewport.prototype.dumpObject = function(obj) {
	if (!this.debug)
		return;
	
	var tab = "&nbsp;&nbsp;&nbsp;&nbsp;";
	for (var item in obj) {
		var str = [];
		str.push(tab);
		str.push(item);
		str.push(": ");
		str.push(obj[item]);
		this.times.push(str.join(''));
	}
}

ListViewport.prototype.toggle = function() {
	if (!this.debugContent) {
		return;
	}
	
	if (this.debugContent.style.display == "none") {
		this.debugContent.style.display = "";
	} else {
		this.debugContent.style.display = "none";
	}
}

ListViewport.prototype.outputTimes = function() {
	if (!this.times)
		return;
		
	var total = 0;
	var html = [];
	html.push("==========<br/>");
	for (var i=0; i<this.times.length; i++) {
		if (typeof(this.times[i].elapsed)=="number") {
			html.push(this.times[i].elapsed);
			html.push("ms");
			var tabnum = 8-(this.times[i].elapsed+"").length
			for (var j=0; j<tabnum; j++) {
				html.push("&nbsp;");
			}
			html.push(this.times[i].label);
			html.push("<br/>");
			total += this.times[i].elapsed;
		} else {
			html.push(this.times[i]);
			html.push("<br/>");
		}
	}
	html.push("----------<br/><b>");
	html.push(total);
	html.push("ms");
	var tabnum = 8-(total+"").length
	for (var j=0; j<tabnum; j++) {
		html.push("&nbsp;");
	}
	html.push("TOTAL TIME FROM REQUEST TO COMPLETION</b>");
	
	if (!this.debugDiv) {
		this.debugDiv = document.createElement('div');
		this.debugDiv.id = this.domId + "_debugDiv";
		this.debugDiv.style.position = "absolute";
		this.debugDiv.style.top = "0px";
		this.debugDiv.style.left = "250px";
		this.debugDiv.style.border = "2px solid red";
		this.debugDiv.style.margin = "3px";
		this.debugDiv.style.padding = "3px";
		this.debugDiv.style.backgroundColor = "white";
		this.debugDiv.style.fontFamily = "Courier New, Courier, monospace";
		var toggle = document.createElement('input');
		toggle.type = "button";
		toggle.value = "Show/Hide Debug Log";
		toggle.className = "btn";
		var self = this;
		toggle.onclick = function() {self.toggle()};
		this.debugDiv.appendChild(toggle);
		this.debugContent = document.createElement('div');
		this.debugDiv.appendChild(this.debugContent);
		document.body.appendChild(this.debugDiv);
	}
	this.debugContent.innerHTML = html.join('');
}

ListViewport.prototype.init = function() {
    /* We need to redefine this function so it will work properly with custom buttons that use the SControl function GETRECORDIDS */
    var self = this;
    Scontrol.prototype.getSelectedRecordIdsFromForm = function () {
        return self.grid.getSelectionModel().selections.keys;
    }
    
	if (this.vf) {
		this.reRender = window[this.domId.replace(":", "_") + '_reRender'];
	}

	this.getReferences();
	this.initializeLinkTemplates();
	this.resize();
	
	var qs = new QueryString();
	if (this.pageState.value == "" && this.rolodexState.value == "" && !qs.get('page') && !qs.get('rolodexIndex')) {
		this.resetTimer();
		this.loading.show();
		this.updatePage(this.payload);
	} else {
		// make the first request
		this.getListData({
			listid: this.listSelect ? this.listSelect.value : this.listId,
			action: "newfilter",
			page: this.pageState.value || qs.get('page'),
			rolodexIndex: this.rolodexState.value || qs.get('rolodexIndex'),
			rowsPerPage: this.rowsPerPage
		});
	}
}

ListViewport.prototype.getReferences = function() {
	this.wrapper = document.getElementById(this.domId + "_wrapper");
	this.listViewport = document.getElementById(this.domId + "_listViewport");
	this.topNav = document.getElementById(this.domId + "_topNav");
	this.filterLinks = document.getElementById(this.domId + "_filterLinks");
	this.rolodex = document.getElementById(this.domId + "_rolodex");
	this.listBody = document.getElementById(this.domId + "_listBody");
	this.bottomNav = document.getElementById(this.domId + "_bottomNav");
	this.listSelect = document.getElementById(this.domId + "_listSelect");
	this.pageState = document.getElementById(this.domId + "_pageState");
	this.rolodexState = document.getElementById(this.domId + "_rolodexState");
	this.exception = document.getElementById(this.domId + "_exception");
	this.buttons = document.getElementById(this.domId + "_buttons");
	this.printLink = document.getElementById(this.domId + "_printLink");
	this.offPageIds = document.getElementById(this.domId + "_offPageIds");

	this.loading = new LoadingScreen(this.listBody, LC.getLabel('Global', 'loading'), this.domId + "_loading");
	this.saving = new LoadingScreen(this.listBody, LC.getLabel('Buttons', 'saving'), this.domId + "_saving");
}

ListViewport.prototype.initializeLinkTemplates = function() {
    this.linkTemplates = {
        newLink : new Ext.Template('<a href="',
                                   UserContext.getUrl("/ui/list/FilterEditPage?ftype={filterType}&retURL={retURL}"),
                                   '">',
                                   LC.getLabel("Filter", "new"),
                                   '</a>').compile(),
        editLink : new Ext.Template('<a href="',
                                    UserContext.getUrl("/ui/list/FilterEditPage?id={filterId}&retURL={retURL}"),
                                    '">',
                                    LC.getLabel("Filter", "edit"),
                                    '</a>').compile(),
        deleteLink : new Ext.Template('<a onclick="return confirm(\'',
                                      LC.getLabel("Filter","DeleteConfirm"),
                                      '\')" ',
                                      'href="',
                                      UserContext.getUrl("/setup/own/deleteredirect.jsp?id={filterId}&delID={filterId}&retURL={delRetURL}&_CONFIRMATIONTOKEN={csrfToken}"),
                                      '">',
                                      LC.getLabel("Buttons", "del"),
                                      '</a>').compile(),
        refreshLink : new Ext.Template('<a id="{domId}_refresh" href="javascript:{jsref}.refreshList()">',
        							   '<b>',LC.getLabel("Filter", "refresh"),'</b>',
        							   '</a>').compile()
    }
}

ListViewport.prototype.refreshList = function() {
    this.grid.getSelectionModel().clearAllSelections();
    this.refreshLink.style.backgroundColor = "";
    this.getListData({page: this.paginator.currentPage, rolodexIndex: this.rolodexIndex});
}

ListViewport.prototype.getListData = function(args) {
	this.resetTimer();
	this.loading.show();
    if (this.xhr) {
    	this.xhr.onreadystatechange = function() {};
    	this.xhr.abort();
    }

	var args = args || {};

	var post = {action : args["action"] || "filter",
				filterId : args["listid"] || (this.filter ? this.filter.id : this.listId),
				filterType : this.filter ? this.filter.type : this.type,
				page : args["page"] || 1,
				rowsPerPage : (args["rowsPerPage"] != null) ? args["rowsPerPage"] : (this.rowsPerPage || ""),
				sort : (args["sort"] != null) ? args["sort"] : "",
				rolodexIndex : (args["rolodexIndex"] != null) ? args["rolodexIndex"] : -1,
				vf : this.vf,
				retURL : window.location.pathname
				};
				
	if (post.action == "newfilter") {
		if(this.filterLinks) {
			this.filterLinks.innerHTML = "&nbsp;";
		}
		if(this.rolodex) {
			this.rolodex.style.visibility = "hidden";
		}
		this.buttons.innerHTML = "";

		document.body.focus(); // take the focus off of the listSelect so scrolling in IE doesn't change the list
	}
    if (this.trace) {
        post.trace = this.trace;
    }

	var self = this;
	this.xhr = XBrowser.postHttpResponse(this.url, function(response) {self.xhrHandler(response.responseText);}, XBrowser.buildPost(post));	
	this.timepoint("AJAX request issued");
	this.dumpObject(post);
}

ListViewport.prototype.xhrHandler = function(responseText) {
	var ldata;
	try {
		ldata = Util.evalAjaxServletOutput(responseText);
	} catch(e) {
		window.location.reload();
	}
	this.updatePage(ldata);
}
	
ListViewport.prototype.updatePage = function(ldata) {
	this.timepoint("entering updatePage");
	if (ldata.exTitle && ldata.exDesc) {
		this.handleException(ldata);
		return;
	}
	
	if (this.trace && ldata.trace) {
		var traceEl = Ext.get("sqltrace");
		Ext.DomHelper.overwrite(traceEl, ldata.trace);
	}
	
    if (ldata.filter && ldata.inlineEditData) {
        this.loadFilter(ldata.filter, ldata.inlineEditData);
        this.timepoint("inline edit data loaded");
    }
	this.retURL = ldata.retURL;
	this.rowsPerPage = ldata.rowsPerPage;
	if(ldata.csrfToken) {
		this.csrfToken = ldata.csrfToken;
	}
	this.drawListData(ldata.listData, ldata.columnWidths);
    this.updateFilterLinks();
    this.timepoint("updated filter links");
    this.updateButtons(ldata.buttons);
    this.timepoint("updated buttons");
    this.updatePrintLink(ldata.printURL);
    this.timepoint("updated print link");
    this.updateSortState(ldata.sortState);
    this.timepoint("updated sort state");
    this.updateRolodex(ldata.rolodexIndex, ldata.sortState);
    this.timepoint("updated rolodex");
    this.updatePaginator(ldata);
    this.timepoint("updated paginator");
	this.updateStateFields();
    this.timepoint("updated state fields");    
	this.resize();	
	this.exception.style.display = "";
	this.loading.hide();
	if(this.reRender && this.xhr) {
		this.reRender();
	}
	this.xhr = null;
	this.timepoint("handling complete");
	this.outputTimes();
}

ListViewport.prototype.handleException = function(ldata) {
	var html = [];
	html.push("<div class='title'>");
	html.push(ldata.exTitle);
	html.push("</div>");
	html.push("<br/>");
	html.push(ldata.exDesc);
	this.exception.innerHTML = html.join('');
	this.exception.style.display = "block";

    if (this.filterLinks) {
        this.filterLinks.style.display = "none";
    }
	this.buttons.style.display = "none";
	if (this.printLink) {
		this.printLink.style.visibility = "hidden";
	}
    if (this.rolodex && this.rolodex.style.visibility != "hidden") {
        this.rolodex.style.visibility = "hidden";
    }
	if (!this.paginator) {
		this.updatePaginator(ldata);
	}
	this.paginator.draw(true);
	this.loading.hide();
}

ListViewport.prototype.updateButtons = function(buttons) {
	if (document.all) {
		// IE is stupid and throws away any leading script tags when setting innerHTML.
		// Adding this hidden element (with content--won't work without it), prevents this.
		buttons.unshift('<span style="display:none" id="', this.domId, '_REMOVE">.</span>');
	}
	this.buttons.innerHTML = buttons.join('');
	if (document.all) {
		// Remove the useless element we just added for useless IE.
		document.getElementById(this.domId + '_REMOVE').removeNode(true);
	}
	Util.evalScriptsUnderElement(this.buttons);
	this.buttons.style.display = "";
}

ListViewport.prototype.updatePrintLink = function(printURL) {
	if (!this.printLink) {
		return;
	}
	
	var pieces = printURL.split("?");
	var url = [];
	url.push("javascript:printWin('");
	url.push(pieces[0]);
	url.push("/x?");
	url.push(pieces[1]);
	url.push("')");
	
	this.printLink.href = url.join('');
	this.printLink.style.visibility = "";
}

ListViewport.prototype.updateStateFields = function() {
	this.pageState.value = this.paginator.currentPage;
	this.rolodexState.value = this.rolodexIndex;
}

ListViewport.prototype.updateFilterLinks = function() {
    var p = {
        filterType: this.filter.type,
        filterId:   this.filter.id,
        domId:		this.domId,
        jsref:		"ListViewport.instances['"+this.domId+"']",
        retURL: 	this.retURL,
        delRetURL:  this.vf?this.retURL:"%2F"+this.filter.entityType,
        csrfToken:  this.csrfToken
    };
    
    var links = [];

	if (this.customizable) {
	    if (this.filter.isCreateNewDisplayed) {
	        links.push(this.linkTemplates.newLink.apply(p));
	    }
	    if (this.filter.editable) {
	        links.push(this.linkTemplates.editLink.apply(p));
	        links.push(this.linkTemplates.deleteLink.apply(p));
	    }
	}
    links.push(this.linkTemplates.refreshLink.apply(p));
    
    this.filterLinks.innerHTML = links.join(" | ");
    this.filterLinks.style.display = "";
    
    this.refreshLink = document.getElementById(this.domId + "_refresh");
}

ListViewport.prototype.updateSortState = function(state) {
   	var view = this.grid.getView();    
	view.sortState = state;
	var colIndex = this.grid.getColumnModel().findColumnIndex(state.field);
	if (colIndex != -1) {
        view.updateSortIcon(colIndex, state.dir);
	}
}

ListViewport.prototype.updateRolodex = function(index, state) {
    this.rolodexIndex = index;
	if (!this.rolodex) {
		return;
	}
    var entries = this.rolodex.childNodes;

    var cm = this.grid.getColumnModel();
    // should be able to get the column by dataIndex...
    var colIndex = cm.findColumnIndex(state.field);
    if (colIndex != -1 && cm.getColumnById(cm.getColumnId(colIndex)).useRolodex) {
        if (this.rolodex.style.visibility == "hidden") {
            this.rolodex.style.visibility = "";
        }
    } else {
        if (this.rolodex.style.visibility != "hidden") {
            this.rolodex.style.visibility = "hidden";
        }
    }
    
    for (var i=0; i < entries.length; i++) {
        if (i==index || (index==-1 && i==entries.length-1)) { // "All" is -1
            entries[i].firstChild.className = "listItemSelected";
        } else {
            entries[i].firstChild.className = "listItemPad";
        }
    }
}

ListViewport.prototype.updatePaginator = function(ldata) {
  	// update Paginator state
	if (!this.paginator) {
		// this must be our initial call to the first page
		var self = this;
		
		this.paginator = new ListPaginator({'listDomId': this.domId,
											'containerIds':[this.domId + '_bottomNav'],
											'recordsPerPage':ldata.rowsPerPage,
											'totalRecords':ldata.totalRowCount,
											'capped':ldata.capped,
											'currentPage':ldata.page,
											'hasCheckbox':this.hasCheckbox,
											'handler': function(pageNum) {
															self.getListData({
																	'page': pageNum,
																	'rolodexIndex': self.rolodexIndex
																})
													   }
										   });
	} else {
		this.paginator.setState({'currentPage': ldata.page,
								 'recordsPerPage': ldata.rowsPerPage,
								 'totalRecords': ldata.totalRowCount,
								 'capped': ldata.capped,
								 'hasCheckbox':this.hasCheckbox
								});
	}
}

ListViewport.prototype.xhrErrorHandler = function(responseText) {
	// TODO
	// might not be necessary.  handle errors from the XHR
}

ListViewport.prototype.loadFilter = function(filter, inlineEditData) {
	this.filter = filter;
	inlineEditData.viewport = this;
	inlineEditData.shownColumns = filter.shownColumns;
	this.inlineEditData = new ListInlineEditData(inlineEditData);
}

ListViewport.prototype.drawListData = function(listData, columnWidths) {
	// take the list data and draw it.
	// "myX" are things that Ext eats.
    var idColumn = listData[ListView.ID_COLUMN];
    var actionColumn = listData[ListView.ACTION_COLUMN];
    var numRows = idColumn.length;

    var hasActions = false;

    // build datastore
    var myData = new Array(numRows);
    var cols = this.filter.shownColumns;
    for( var row = 0; row < myData.length; row++) {
        myData[row] = [];
        myData[row].push(idColumn[row]);
        if (actionColumn[row] != null) { hasActions = true; }
        myData[row].push(actionColumn[row]);
        for (var col = 0; col < cols.length; col++) {
        	myData[row].push(listData[cols[col].columnName][row]);
        }
    }
    this.timepoint("datastore prepared");

    // build fields and columns
    this.hasCheckbox = this.filter.showCheckBox || this.inlineEditData.isMassEditable;
    var sm = new Sfdc.grid.CheckboxSelectionModel({menuDisabled: true});
    var myFields = [];
    var myColumns = [];
    if (this.hasCheckbox) {
        myColumns.push(sm);
    }
    
    myFields.push({name: ListView.ID_COLUMN});
    myColumns.push({
        header: 'ID',
        hidden: true,
        dataIndex: ListView.ID_COLUMN,
        id: ListView.ID_COLUMN
    });
    
    myFields.push({name: ListView.ACTION_COLUMN});
    myColumns.push({
        header: LC.getLabel("Global", "action"),
        dataIndex: ListView.ACTION_COLUMN,
        id: ListView.ACTION_COLUMN,
        width: 1,
        hidden: !hasActions,
        menuDisabled: true,
        fixed: true,
        css: "font-weight: bold;",
        renderer: function(val) {return val ? val.join(" | ") : "";}
    });

    var colWidths = columnWidths || [];
    
    for (var i = 0; i < cols.length; i++) {
    	if (!colWidths[i]) colWidths[i] = ListViewport.DEFAULT_COLUMN_WIDTH;
    	// if there is a ListFilterColumn use it to get the id, otherwise just use the name
        var lfc = this.inlineEditData.getColumnById(cols[i].columnName);
        var id = lfc ? lfc.getFieldId() : cols[i].columnName;
    	myFields.push({name: cols[i].columnName});
    	myColumns.push({
    	    header: cols[i].label,
    	    width: colWidths[i],
    	    dataIndex: cols[i].columnName,
    	    id: id.replace(/\./g, "_"),
            menuDisabled: true,
    	    isSortable: cols[i].isSortable,
    	    useRolodex: cols[i].useRolodex,
    	    renderer: function(val) {return typeof val == "object" ? val[0] : val;}
    	});
    }
   	this.timepoint("fields and columns prepared");

	if (!this.grid) {
	    // initial page load
        var listeners = {};
        listeners.columnmove = { fn: this.extHandler.columnMove, scope: this};
        listeners.columnresize = { fn: this.extHandler.columnResize, scope: this};
        listeners.headerclick = { fn: this.extHandler.headerClick, scope: this};
        listeners.celldblclick = { fn: this.extHandler.cellDblClick, scope: this}
        listeners.cellmouseover = { fn: this.extHandler.cellMouseOver, scope: this}
        listeners.cellmouseout = { fn: this.extHandler.cellMouseOut, scope: this}

		this.grid = new Ext.grid.GridPanel({
            viewport: this, // maintaining a convenience reference to the viewport
            id: this.filter.id + '_grid',
            cm: new Ext.grid.ColumnModel(myColumns),
            sm: sm,
            store: new Ext.data.SimpleStore({
            	id: 0,
            	fields: myFields
            }),
            view: new Sfdc.grid.GridView({
                emptyText: LC.getLabel("List","none"),
                sortClasses: ["ASC", "DESC"]
            }),
	    	listeners: listeners,
	    	width: this.listBody.offsetWidth
	    });
        this.grid.addEvents("cellMouseOver", "cellMouseOut");
        this.timepoint("grid initialized");
        this.showRPPWarning();
	} else if ((this.filter.id + '_grid') != this.grid.id) {
	    // loading a new filter
	    this.grid.getSelectionModel().clearAllSelections();
	    
	    var store = new Ext.data.SimpleStore({
	        	id: 0,
				fields: myFields
	    	});
	    var columnModel = new Ext.grid.ColumnModel(myColumns);
	    this.grid.reconfigure(store, columnModel);
	    this.grid.id = this.filter.id + "_grid";
	    this.timepoint("grid reconfigured");
	}
	this.grid.render(this.listBody.id);
	this.timepoint("grid rendered");

	if (myData.length > 0) {
		this.grid.getStore().loadData([myData[0]]);
		this.timepoint("first row loaded into grid");
	}

	
	// make the action column fit its longest row
	var cm = this.grid.getColumnModel();
    var actionIndex = cm.getIndexById(ListView.ACTION_COLUMN);
    this.grid.view.sizeColumnToContent(actionIndex);
    this.timepoint("action column sized");

	var cmTotalWidth = cm.getTotalWidth();
	this.timepoint("cm total width got");
	var gridInnerWidth = this.grid.getInnerWidth();
	this.timepoint("grid inner width got");
	
    if ((cmTotalWidth < gridInnerWidth) && !columnWidths) {
    	this.grid.view.fitColumns();
    	this.timepoint("columns fit");
    }
    
    this.grid.getStore().suspendEvents();
	this.grid.getStore().loadData(myData);
    this.grid.getStore().resumeEvents();
	this.timepoint("all data loaded into grid");

	// add cellmouseover, cellmouseout listeners
	this.grid.body.on("mouseover", function(e) {
	    this.grid.processEvent("mouseover", e);
	}, this);
	this.grid.body.on("mouseout", function(e) {
	    this.grid.processEvent("mouseout", e);
	}, this);
    this.timepoint("cell listeners added");
	
	if (this.draggable) {
		this.initdd();
	}
}

ListViewport.prototype.initdd = function() {
	var self = this;
	this.drag = new Ext.dd.DragZone(this.grid.getEl(),  {
		containerScroll: true,
		scroll: false,
		rowId: '',
		getDragData: function(e) {
			var t = e.getTarget('div.x-grid3-row');
			if (t) {
				var firstCol = self.getFilterColumns()[0];
				
				var selector = ".x-grid3-col-"+firstCol.id;
				var returnTo = Ext.get(t).select(selector, true).elements[0];
				
				var ddel = document.createElement('div');
				ddel.className = "dragElement";
				var val = self.drag.row.data[firstCol.dataIndex];
				ddel.innerHTML = (typeof val == "object") ? val[0] : val;
				return {
					ddel: ddel,
					rowId: self.drag.row.id,
					repairXY: returnTo.getXY()
				};
			}
		},
        getRepairXY: function() {
            return this.dragData.repairXY;
        }
	});

	this.grid.on('rowmousedown', function(g, index, e) {self.drag.row = g.getStore().getAt(index);})
}

ListViewport.prototype.getHOffset = function() {
	var hOffset = 0;
	hOffset += Ext.fly(this.topNav).getHeight();
	hOffset += Ext.fly(this.bottomNav).getHeight();
	hOffset += Ext.fly(this.listViewport).getBorderWidth('tb');
	hOffset += Ext.fly(this.listBody).getBorderWidth('tb');
	return hOffset;
}

ListViewport.prototype.resize = function() {
	this.shrinkStore();
	var hOffset = this.getHOffset();
	
	var parent = Ext.fly(this.wrapper).parent();
	
	var hgoal = 0;
	if (this.vf) {
		hgoal = this.height || parent.getHeight(true);
	} else {
		// if not in VF pages, fit to window, minus page header and a 10px bottom buffer
		hgoal = document.documentElement.clientHeight - Ext.fly(this.wrapper).getTop() - 10;
	}
	var h = hgoal - hOffset;
	var hpx = h + "px";

	// hide grid briefly so parent will reflow with proper width
	if (this.grid) {
		this.grid.el.dom.style.display = "none";
	}
	var wgoal = this.width || parent.getWidth(true);
	var wpx = wgoal + "px";

	this.timepoint("resize overhead");
	
	this.listBody.style.height = hpx;
	if (this.width) {
		this.wrapper.style.width = wpx;
	}
	this.timepoint("listBody resized");
	
	this.exception.style.height = hpx;
	if (this.width) {
		this.exception.style.width = wpx;
	}
	this.timepoint("exception resized");
	
	if (this.loading.transparantElement) {
		this.loading.transparantElement.style.height = hpx;
		if (this.width) {
			this.loading.transparantElement.style.width = wpx;
		}
		this.timepoint("loading resized");
	}
	
	if (this.grid) {
		this.grid.el.dom.style.display = "";
	    this.grid.suspendEvents();
	    this.timepoint("suspended events");
		this.grid.setHeight(h);
		this.timepoint("grid height resized");
		var w = wgoal - Ext.fly(this.listViewport).getBorderWidth("lr");
		this.grid.setWidth(w);
		this.timepoint("grid width resized");
	    this.grid.resumeEvents();
	    this.timepoint("resumed events");
		this.unshrinkStore();
	
		this.sizeIfNoData();
	}
}

ListViewport.prototype.redefineSidebarPin = function() {
	var self = this;

	Sidebar.prototype.theSidebar.pin = function() {
		Sidebar.prototype.pin.apply(Sidebar.prototype.theSidebar);
		self.resize();
	};
}

ListViewport.prototype.beforeSave = function() {
    this.saving.show();
}

ListViewport.prototype.afterSave = function(saved, column) {
    if (saved && saved.length > 0) {
		this.refreshLink.style.backgroundColor = "#FFE324";

        var value = column.getDisplayValue();
        if (value === "") {
            value = "&nbsp;";
        }
        var fieldId = column.getFieldId();
        var composite = new Ext.CompositeElement();
        for (var i = 0; i < saved.length; i++) {
            var id = saved[i];
            var cell = Ext.get(getElementByIdCS(saved[i] + "_" + fieldId));
            if (cell) {
                composite.add(cell.parent())
                cell.update(value);
                var record = this.grid.getStore().getById(saved[i]);
                // store is indexed by column name, not field id
                if (record && record.data[column.columnName]) {
                    record.data[column.columnName] = value;
                }
            }
        }
        var color = this.grid.getSelectionModel().getCount() > 0 ? "#dfe8f6" : "#ffffff";
        composite.highlight("#ffffcc", {
            endColor: color,
            duration: 2.5,
            concurrent: true
        });
    }
    this.saving.hide();
}

// gets the columns in order, ignoring checkbox, id, and action columns
ListViewport.prototype.getFilterColumns = function() {
	return this.grid.getColumnModel().getColumnsBy(function(c,i) {return (c.id != "checkbox" && c.id != ListView.ID_COLUMN && c.id != ListView.ACTION_COLUMN)});
}
ListViewport.prototype.extHandler = {
	columnMove : function (oldIndex, newIndex) {
        if (this.filter.id !== Udd.EMPTY_KEY) {
    		var colObjs = this.getFilterColumns();
    		var cols = [];

    		for (var i=0; i < colObjs.length; i++) {		    
    		    cols.push(colObjs[i].dataIndex);
    		}

            var post = {action: "reorderColumns",
                        filterId : this.filter.id,
                        cols : cols};
    		if (this.customizable) {
                XBrowser.postHttpResponse(this.url, function(response) {}, XBrowser.buildPost(post));
            }
        }

		var view = this.grid.getView();
		view.updateSortIcon(this.grid.getColumnModel().findColumnIndex(view.sortState.field), view.sortState.dir);
	},

	columnResize : function (colIndex, newsize) {
	    if (this.filter.id !== Udd.EMPTY_KEY) {
            var colObjs = this.getFilterColumns();

            var widths = []
            for (var i=0; i < colObjs.length; i++) {		    
                widths.push(colObjs[i].width);
            }

            var post = {action: "setColumnWidths",
            			filterId : this.filter.id,
            			widths: widths};

            XBrowser.postHttpResponse(this.url, function(response){}, XBrowser.buildPost(post));
			this.sizeIfNoData();
        }
	},

    cellDblClick : function (grid, rowIndex, columnIndex, event) {
        if (this.inlineEditData.isEditable) {
            var colId = grid.getColumnModel().getDataIndex(columnIndex);
            var column = this.inlineEditData.getColumnById(colId);
            if (column && column.state == InlineEditState.EDIT) {
                var sm = this.grid.getSelectionModel();
                if (sm.getCount() == 0 || sm.selectRow(rowIndex, this.inlineEditData.isMassEditable)) {
                    var row = this.grid.getStore().getAt(rowIndex);
                    var rowId = row.get(ListView.ID_COLUMN);
                    var initialValue = row.get(column.columnName);
                    this.inlineEditData.openColumn(rowId, colId, typeof initialValue == "object" ? initialValue[1] : null);
                }
            }
        }
	},

    cellMouseOver : function (grid, rowIndex, columnIndex, event) {
        if (this.inlineEditData.isEditable) {
            var column = this.inlineEditData.getColumnById(grid.getColumnModel().getDataIndex(columnIndex));
            if (column) {
                var css = column.state.cssClass;
                Ext.fly(this.grid.getView().getCell(rowIndex, columnIndex)).replaceClass(css, css + "On");
            }
        }
    },

    cellMouseOut : function (grid, rowIndex, columnIndex, event) {
        if (this.inlineEditData.isEditable) {
            var column = this.inlineEditData.getColumnById(grid.getColumnModel().getDataIndex(columnIndex));
            if (column) {
                var css = column.state.cssClass; 
                Ext.fly(this.grid.getView().getCell(rowIndex, columnIndex)).replaceClass(css + "On", css);
            }
        }
    },

	headerClick : function (grid, columnIndex) {
        var cm = grid.getColumnModel();
	    var column = cm.getColumnById(cm.getColumnId(columnIndex));
	    var view = grid.getView();	    
	    if (!column.isSortable || view.headersDisabled) {
	        return;
	    }
	    
        var field = column.dataIndex;	    

        if (field) {
            if (view.sortState.field == field && view.sortState.dir == "ASC") {
                this.getListData({
                	sort: "-"+field,
                	page: this.paginator.currentPage,
                	rolodexIndex: this.rolodexIndex
                });
                view.updateSortIcon(columnIndex, "DESC");
                view.sortState.dir = "DESC";
            } else {
                this.getListData({
                	sort: field,
                	page: this.paginator.currentPage,
                	rolodexIndex: (view.sortState.field == field) ? this.rolodexIndex : -1
                });
                view.updateSortIcon(columnIndex, "ASC");
                view.sortState = {field: field, dir: "ASC"};
            }
        }
	}
}

ListViewport.prototype.verify = function(errorMessage) {
    if (this.grid.getSelectionModel().selections.length > 0) {
        return true;
    } else {
        alert(errorMessage);
        return false;
    }
}

ListViewport.prototype.showRPPWarning = function() {
	if (this.vf || this.rowsPerPage <= 100 || UserContext.userPreferences.getBoolean("HideRPPWarning")) {
		return;
	}
	
	if (!ListViewport.dialog) {
		var self = this;
		ListViewport.dialog = new SimpleDialog("RPPWarning");
        ListViewport.dialog.displayX = true;
        ListViewport.dialog.setWidth(520);
        ListViewport.dialog.extraClass = "RPPDialog";
	    ListViewport.dialog.setTitle(LC.getLabel('RPPDialog', 'title'));
        ListViewport.dialog.createContent = function() {
    	    var content = document.getElementById(this.getContentId());
			var html = [];
			html.push("<h2 id='");
			html.push(ListViewport.dialog.id);
			html.push("Header'>");
			html.push(ListViewport.dialog.header);
			html.push("</h2>");
			html.push("<div id='");
			html.push(ListViewport.dialog.id);
			html.push("Inner'>");
			// begin inner content
			html.push("<div class='message warningM4'><table cellspacing='0' cellpadding='0' border='0' class='messageTable'><tr><td>");
			html.push("<img title='Warning' class='msgIcon' src='/s.gif' alt='");
			html.push(LC.getLabel('Icon', 'WARNING'));
			html.push("'/></td>");
			html.push("<td class='headerCell'><h4>");
			html.push(LC.getLabel('RPPDialog', 'yourRPP', self.rowsPerPage));
			html.push("</h4></td></tr>");
			html.push("<tr><td></td><td><div>");
			html.push(LC.getLabel('RPPDialog', 'message'));
			html.push("</div>");
			html.push("</td></tr></table></div>");
			
			html.push("<div class='radioDiv'>");
			html.push("<div class='radio'><input type='radio' name='RPPRadio' id='RPPChange' checked='checked'><label for='RPPChange'>");
			html.push(LC.getLabel('RPPDialog', 'change'));
			html.push("</label>");
			
		    html.push("<select class='RPPSelect' name='RPPSelect' id='RPPSelect'>");
		    var opts = [10, 25, 50, 100];
			for (var i=0; i<opts.length; i++) {
			    html.push("<option value='");
			    html.push(opts[i]);
			    html.push("'");
			    if (opts[i] == 100) {
			    	html.push(" selected")
			    }
			    html.push(">");
			    html.push(opts[i]);
				html.push("</option>");
			}
		    html.push("</select></div>");
		    html.push("<div class='radio'><input type='radio' name='RPPRadio' id='RPPNoChange'><label for='RPPNoChange'>");
		    html.push(LC.getLabel('RPPDialog', 'nochange'));
		    html.push("</label></div>");
		    html.push("</div>");
		
		    html.push("<div class='buttons'>");
		    html.push("<input class='btn' type='button' value='");
		    html.push(LC.getLabel("Buttons", "save"));
		    html.push("' id='RPPSaveButton'><input class='btn' type='button' value='");
		    html.push(LC.getLabel("Buttons", "cancel"));
		    html.push("' id='RPPCancelButton'>");
		    html.push("</div>");
		    // end inner content
			html.push("</div>");
			content.innerHTML = html.join("");
			
			document.getElementById('RPPChange').onclick = function() { document.getElementById('RPPSelect').disabled = ""};
		    document.getElementById('RPPNoChange').onclick = function() {document.getElementById('RPPSelect').disabled = "true"};
		    document.getElementById('RPPCancelButton').onclick = function() {ListViewport.dialog.hide()};
		    document.getElementById('RPPSaveButton').onclick = function() {
		    	if (document.getElementById('RPPNoChange').checked) {
	    		    UserContext.userPreferences.setBoolean("HideRPPWarning", true);
		    	} else {
		    		self.getListData({
		    			rowsPerPage: document.getElementById('RPPSelect').value,
						rolodexIndex: self.rolodexIndex
					});
		    	}
		    	ListViewport.dialog.hide();
		    };
		    
		    ListViewport.dialog.show();
        }
        ListViewport.dialog.register();
	}
}

ListViewport.instances = {};

ListViewport.addListViewport = function(what) {
	ListViewport.instances[what.domId] = what;
}

/**
 * CRT Object selection UI
 *
 * @author tkim
 * @since 148
 */
 
/**
 * This JS class manages the object selection picklists
 */
CrtObjects.DOT_SEPARATOR = CrtConstants.PICKLIST_VALUE_TABLE_FIELD_SEPARATOR;
CrtObjects.ID_SEPARATOR = CrtConstants.PICKLIST_VALUE_ID_SEPARATOR;

CrtObjects.init = function(relationships) {
    var picks = new Array();
    for(var iPicklist = 0; iPicklist < CrtConstants.MAX_OBJECTS; iPicklist++) {
        var pick = document.getElementById(CrtConstants.OBJECT_PREFIX + iPicklist);
        picks[iPicklist] = pick;
    }
    return new CrtObjects(relationships, picks);
}

/**
  we require a map, given as JSON:

  Map<String, Array of Relationship> map from Object to Array of Relationship
  Relationship = tuple (name/value, label)

    var relationships = {
        "Account" : [
            { value : "Contact.Account", label: "Contacts" },
            { value : "Opportunity.Account", label: "Opportunities } ],
        "Contact": [
        ]
    };

For a given relationship value, for example, "Contact.Account", the substring
preceding the dot is necessarily another element in the map.

*/
function CrtObjects(relationships, picks) {
    this.relationships = relationships;
    this.picks = picks;
    this.originalValues = CrtObjects.getSelectedValues(picks);

// for debugging:
/*
    var self = this;
    for(var iPicklist = 0; iPicklist < picks.length; iPicklist++) {
        addEvent(this.picks[iPicklist], 'change', this.getUpdatePicklistsClosure(iPicklist), false);
    } */
}

// public
CrtObjects.prototype.getPicklist = function(iPicklist) {
    return this.picks[iPicklist];
}

// public
CrtObjects.prototype.getValue = function(iPicklist) {
    return CrtObjects.getSelectedValue(this.picks[iPicklist]);
}

/** this is necessary to make iPicklist effectively like a final variable
    by taking a snapshot of the stack frame */
CrtObjects.prototype.getUpdatePicklistsClosure = function(iPicklist) {
    var self = this;
    return function() { self.updatePicklists(iPicklist) };
}

/**
 if picklist i changes, then:
     if this is not the last picklist:
         - set all picklists j > i to null value (or maybe to a previous value?)
         - set the options for the next picklist i+1 to the relationship values
 */
CrtObjects.prototype.updatePicklists = function(iPicklist) {
    // clear all picklists j > i
    for(var j = iPicklist + 1; j < CrtConstants.MAX_OBJECTS; j++) {
       this.picks[j].options.length = 1; // leave the --None-- option
    }

    if (iPicklist < (CrtConstants.MAX_OBJECTS - 1)) {
        // set the options for the next picklist i+1 to the relationships
        var value = CrtObjects.getSelectedValue(this.picks[iPicklist]);
        if (value != '') {
	        var object = this.parseObject(CrtObjects.getSelectedValue(this.picks[iPicklist]));
	        var rels = this.relationships[object];
            for(var iRel = 0; iRel < rels.length; iRel++) {
                var rel = rels[iRel];
                var relValue = this.swapOriginalValue(iPicklist + 1, rel.value);
                var options = this.picks[iPicklist + 1].options;
                options[options.length] = new Option(rel.label, relValue);
            }
        }
    }
}

/* restore the original value that includes the ID, if this is the same as the original value */
CrtObjects.prototype.swapOriginalValue = function(iChildPicklist, relationshipValue) {
    var ret = relationshipValue;
    // is the parent set to the original value?  only do the swap if the parent
    // is also set to an original value.  if the parent set to a new value then
    // the child never corresponds to the original value.
    var parentPicklistValue = CrtObjects.getSelectedValue(this.picks[iChildPicklist - 1]);
    if (parentPicklistValue.indexOf(CrtObjects.ID_SEPARATOR) >= 0) {
        // if the parent has an ID, then it must be an original value
        // so test this child relationship for swap
        var originalChildValue = this.originalValues[iChildPicklist];
        originalChildValue = originalChildValue.substring(0, originalChildValue.indexOf(CrtObjects.ID_SEPARATOR)); // strip the ID for the test
        if (relationshipValue == originalChildValue) {
            ret = this.originalValues[iChildPicklist];
        }
    }
    return ret;
}

// private
// get the selected value of a select element
CrtObjects.getSelectedValue = function(selectElement) {
    return selectElement.selectedIndex < 0 ? null : selectElement.options[selectElement.selectedIndex].value;
}

// private
CrtObjects.getSelectedValues = function(picks) {
    var originalValues = new Array();
    for(var iPick = 0; iPick < picks.length; iPick++) {
        originalValues[iPick] = CrtObjects.getSelectedValue(picks[iPick]);
    }
    return originalValues;
}

// private
// grab the object from a string like "Contact.Account" or "Contact.Account|071xxxxxx"
CrtObjects.prototype.parseObject = function(picklistValue) {
    var value;
    var iDot = picklistValue.indexOf(CrtObjects.DOT_SEPARATOR);
    var iPipe = picklistValue.indexOf(CrtObjects.ID_SEPARATOR);
    if (iDot >= 0) {
        value = picklistValue.substring(0, iDot);
    } else if (iPipe >= 0) {
        // No dot (first picklist of root objects) so just take the value, minus the pipe-ID part
        value = picklistValue.substring(0, iPipe);
    } else {
        // Not even a pipe, so take the whole thing
        value = picklistValue;
    }
    return value;
}
/**
	@param object		required. object, The object to be faded
	@param testMin		required. function(object, currVal), should return true if the object is completely faded out
	@param testMax  	required. function(object, currVal), should return true if the object is completely faded in
	@param timestep 	required. number, The interval between steps, in milliseconds
	@param nextStep		required. function(currVal, sign), given the current value and a direction, return the next value.
								  sign will be positive for fadeIn, negative for fadeOut.  Any return value will be saved 
								  to currVal.
	@param increment	requried. function(object, nextVal) the increment function.  Should change the property
							      of the object to nextVal (which is the value returned by nextStep).  
	@param initVal		optional. number, an initial value for currVal.
	@param finalMin		optional. function(object),  Will be called at the end of fadeOut
	@param finalMax		optional. function(object), Will be called at the end of fadeIn
    @param startIn      optional. function(object), Wtill be called before a jumpIn or fadeIn
*/
function Fader(object, testMin, testMax, timestep, nextStep, increment, initVal, finalMin, finalMax, startIn) {	
	var self = this;
	
	if (!(object && testMin && testMax && timestep && nextStep && increment)){
		//required arguments
		return null;
	}
	
	this.object = object;
	this.testMin = testMin;
	this.testMax = testMax;
	this.timestep = timestep;
	this.nextStep = nextStep;
	this.increment = increment;
	this.currVal = initVal;
	this.finalMin = finalMin;
	this.finalMax = finalMax;
	this.startIn = startIn;
	
	this.inId = -1;
	this.outId = -1;
	
	this.position = 'out';
	
	this.fadeIn = function(){
		if (self.startIn) self.startIn(this.object);
		if (self.outId >= 0){
			clearInterval(self.outId);
			self.outId = -1;
		}
		if (this.inId < 0){
			self.inId = setInterval(fadeInCaller, self.timestep);
			self.position = 'moving_in';
 		} 
	}
	
	this.fadeOut = function() {
		if (self.inId >= 0){
			clearInterval(self.inId);
			self.inId = -1;
		}
		if (self.outId < 0){
			self.outId = setInterval(fadeOutCaller, self.timestep);
			self.position = 'moving_out';
 		} 
	}
	
	function fadeInCaller(){
		self.fadeInHelp();
	}
	
	function fadeOutCaller(){
		self.fadeOutHelp();
	}
	
	this.isMoving = function() {
		return (this.inId >= 0 || this.outId >= 0);
	}
	
	/*
	return one of 'in', 'out', 'moving_in', 'moving_out', or 'stopped'
	*/
	this.getPosition = function(){
		return self.position;
	}
}

Fader.prototype.fadeInHelp = function() {
	var nextVal = this.nextStep(this.currVal, 1);
	if (this.testMax(this.object, nextVal)){
		var finalVal = this.finalMax && this.finalMax(this.object);
		if (typeof finalVal == "number") { this.currVal = finalVal; }
		clearInterval(this.inId);
		this.inId = -1;
		this.position = 'in';
		return;
	} 
	this.increment(this.object, nextVal);
	this.currVal = nextVal;
};

Fader.prototype.fadeOutHelp = function() {
	var nextVal = this.nextStep(this.currVal, -1);
	if (this.testMin(this.object, nextVal)){
		var finalVal = this.finalMin && this.finalMin(this.object);
		if (typeof finalVal == "number") { this.currVal = finalVal; }
		clearInterval(this.outId);
		this.outId = -1;
		this.position = 'out';
		return;
	}
	this.increment(this.object, nextVal);
	this.currVal = nextVal;
};

Fader.prototype.stopFade = function() {
	if (this.inId >= 0){
		clearInterval(this.inId);
		this.inId = -1;
	}
	if (this.outId >= 0){
		clearInterval(this.outId);
		this.outId = -1;
	}
	this.position = 'stopped';
};

Fader.prototype.jumpIn = function() {
	if (this.startIn) this.startIn(this.object);
	var newCur = null;
	if (this.finalMax) {newCur = this.finalMax(this.object); }
	if (newCur !== null) { this.currVal = newCur;}
	this.position = 'in';
};

Fader.prototype.jumpOut = function() {
	var newCur = null;
	if (this.finalMin) {newCur = this.finalMin(this.object);}
	if (newCur !== null) { this.currVal = newCur; }
	this.position = 'out'
};
	
var HTMLTreeNode = function(){}

HTMLTreeNode.prototype.toggleHTMLTree = function(topic) {

    var obj = HTMLTreeNode.prototype.getNodeChild(topic);
    if (obj != null) {
        var visible = HTMLTreeNode.prototype.isVisible(obj);
        if (visible) {
        	HTMLTreeNode.prototype.close(obj, topic);
		    SetupTreeNode.prototype.removeFromOpenSetup(topic);
        } else {
        	HTMLTreeNode.prototype.open(obj, topic);
		    SetupTreeNode.prototype.addToOpenSetup(topic);	
        }
    }
}

HTMLTreeNode.prototype.isVisible = function(obj){
	return obj.style.display != 'none';
}

HTMLTreeNode.prototype.setVisible = function(obj, visible){
	if (obj){
		if (visible){
			obj.style.display = '';
		} else {
			obj.style.display = 'none';
		}
	}
}

HTMLTreeNode.prototype.getNode = function(topic){
	
    var informationDiv=document.getElementById('treeInformation');
    if (informationDiv == null){
        return;
    }
	
    return document.getElementById(topic);
	
}

HTMLTreeNode.prototype.getNodeChild = function(topic){
	
    var informationDiv=document.getElementById('treeInformation');
    if (informationDiv == null){
        return;
    }
	
	var id = topic + informationDiv.getAttribute('child');
    return document.getElementById(id);
	
}

HTMLTreeNode.prototype.open = function(obj, topic) {
	
    var informationDiv=document.getElementById('treeInformation');
    if (informationDiv == null){
        return;
    }
	
    obj.style.display='block';

    var key=document.getElementById(topic + informationDiv.getAttribute('icon'));
    if (key != null){
	    var currentTitle = key.getElementsByTagName('img')[0].title;
	    var image=key.getElementsByTagName('img')[0];
	    image.src=informationDiv.getAttribute('minusSrc');
	    image.title = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('collapse'));
	    image.alt = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('collapse'));
    }
}

HTMLTreeNode.prototype.close = function(obj, topic) {

    var informationDiv=document.getElementById('treeInformation');
    if (informationDiv==null){
        return;
    }

    obj.style.display='none';

    var key = document.getElementById(topic + informationDiv.getAttribute('icon'));
    if (key != null){
	    var currentTitle = key.getElementsByTagName('img')[0].title;
	    var image=key.getElementsByTagName('img')[0];
	    image.src=informationDiv.getAttribute('plusSrc');
	    image.title = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('expand'));
	    image.alt = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('expand'));
    }
}

HTMLTreeNode.prototype.changePreTitle = function(currentTitle, preTitle){
    return preTitle+" "+currentTitle.substr(currentTitle.indexOf('-'));
}

// if section is null or invalid there is a fall-back mechanism that will 
// attempt to open up needed section by the topic given.
// HTMLTreeNode.prototype.openHTMLTree() is referenced from functions.js and help.js
HTMLTreeNode.prototype.openHTMLTree = function(sectionEsc,topicEsc) {
    var section = (sectionEsc) ? unescapeJsInHtml(sectionEsc) : null;
    var topic = (topicEsc) ? unescapeJsInHtml(topicEsc) : null;
    var informationDiv = document.getElementById('treeInformation');
    if (informationDiv==null){
        return;
    }
    // highlight the needed topic
    if (topic!=null){
         HTMLTreeNode.prototype.unHighlightAll();

         var leaf = document.getElementById(topic +informationDiv.getAttribute('leaf'));
         if (leaf && leaf.className){
             leaf.className="setupHighlightLeaf"	;
             informationDiv.setAttribute('lastHighlight',topic +informationDiv.getAttribute('leaf'));
         }
     }
     // get the secton to expand
     var obj=document.getElementById(section +informationDiv.getAttribute('child'));
     if (obj==null && topic!=null){

         /**
         * Try to open up a secton by going to the parent
         */
         var leaf = document.getElementById(topic +informationDiv.getAttribute('leaf'));
         if (leaf!=null){
             var divParent = leaf.parentNode;
            if (divParent!=null && divParent.id.indexOf(informationDiv.getAttribute('child')) >0){
                section = divParent.id.substr(0,divParent.id.indexOf(informationDiv.getAttribute('child')));
                obj=divParent;
            }
         }
     }
    if (obj != null) {
        var key=document.getElementById(section +informationDiv.getAttribute('icon'));
        var currentTitle = key.getElementsByTagName('img')[0].title;
        obj.style.display='block';
        var image=key.getElementsByTagName('img')[0];
        image.src=informationDiv.getAttribute('minusSrc');
        image.title = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('collapse'));
        image.alt = HTMLTreeNode.prototype.changePreTitle(currentTitle,informationDiv.getAttribute('collapse'));
        var divParent = obj.parentNode;
        if (divParent!=null){
            divParent = divParent.parentNode;
            if (divParent!=null && divParent.id.indexOf(informationDiv.getAttribute('child')) >0){
                var section = divParent.id.substr(0,divParent.id.indexOf(informationDiv.getAttribute('child')));
                HTMLTreeNode.prototype.openHTMLTree(section,null);
            }
      }
      if (topic!=null){
            window.scrollTo(0,key.offsetTop)
        }
    }else if (topic!=null){
        // if this topic section was not part of any section
        var leaf = document.getElementById(topic + informationDiv.getAttribute('leaf'));
        if (leaf!=null){
            window.scrollTo(0,leaf.offsetTop)
        }
    }
}

HTMLTreeNode.prototype.unHighlightAll = function(){
         var informationDiv = document.getElementById('treeInformation');
         if (informationDiv==null){
            return;
         }
        var lastHighlight = informationDiv.getAttribute('lastHighlight');
        if (lastHighlight==null){
            return;
        }
        var elementH =  document.getElementById(lastHighlight);
        if (elementH!=null && elementH.className==informationDiv.getAttribute('highlightClass')){
            elementH.className =informationDiv.getAttribute('leafClass');
        }
}


HTMLTreeNode.prototype.populateTheTreeInformation = function(font,child,icon,leaf,expand,collapse,plusSrc,minusSrc,highlightClass,leafClass){

    var informationDiv = document.getElementById('treeInformation');
    if (informationDiv==null){
        return;
    }
    informationDiv.setAttribute('font',font);
    informationDiv.setAttribute('child',child);
    informationDiv.setAttribute('icon',icon);
    informationDiv.setAttribute('leaf',leaf);
    informationDiv.setAttribute('expand',expand);
    informationDiv.setAttribute('collapse',collapse);
    informationDiv.setAttribute('plusSrc',plusSrc);
    informationDiv.setAttribute('minusSrc',minusSrc);
    informationDiv.setAttribute('highlightClass',highlightClass);
    informationDiv.setAttribute('leafClass',leafClass);
    informationDiv.setAttribute('lastHighlight','none');
}








var Captcha = {
    formName : "",
    submitButtonName : "",
    publicKey : "",
    recaptchaLang : "",
    
    dialog : null,
    
    verified : false,

    // called when you click on the captcha button
    click : function(formName, submitButtonName, publicKey, helpHref, recaptchaLang) {
        Captcha.formName = formName;
        Captcha.submitButtonName = submitButtonName;
        Captcha.publicKey = publicKey;
        Captcha.recaptchaLang = recaptchaLang;
        
    	if (Captcha.verified) {
    		Captcha.proceed();
    		return;
    	}
    	
    	if (typeof Recaptcha == "undefined") {
    	    // recaptcha.js failed to load, recaptcha.net might be down
    	    Captcha.submitClientError();
    	    return;
    	}
    	
    	if (!Captcha.dialog) {
        	Captcha.dialog = new SimpleDialog("captcha_dialog", true);
        	Captcha.dialog.enter = Captcha.submit;
        	Captcha.dialog.setupDefaultButtons();
        	Captcha.dialog.overrideButton(0, LC.getLabel("Buttons", "submit"), "Captcha.submit()");
        	Captcha.dialog.setWidth('350px');
        	Captcha.dialog.register(); // this calls createDialog
        	var html = [];
        	html.push('<div id="recaptcha_widget">');
        	html.push(LC.getLabel("CaptchaElement", "dialog"));
        	html.push('<div id="recaptcha_image"></div>');
        	html.push('<div id="incorrect" style="display:none;color:red">');html.push(LC.getLabel("CaptchaElement", "incorrect"));html.push('</div>');
        	html.push('<table class="captchaContent" border="0" cellpadding="0" cellspacing="0">');
        	html.push('  <tr><td><span class="recaptcha_only_if_image">');html.push(LC.getLabel("CaptchaElement", "imagePrompt"));html.push('</span>');
        	html.push('          <span class="recaptcha_only_if_audio">');html.push(LC.getLabel("CaptchaElement", "audioPrompt"));html.push('</span>');
        	html.push('          <input id="recaptcha_response_field" name="recaptcha_response_field" type="text">');
        	html.push('      </td>');
        	html.push('      <td style="width:25px;border-left:none;cursor:pointer">');
        	html.push('          <img src="' + UserContext.getUrl("/img/recaptcha_refresh.gif") + '" alt="' + LC.getLabel("CaptchaElement", "refresh") + '" title="' + LC.getLabel("CaptchaElement", "refresh") + '" onclick="Recaptcha.reload()">');
        	html.push('          <img class="recaptcha_only_if_image" src="' + UserContext.getUrl("/img/recaptcha_audio.gif") + '" alt="' + LC.getLabel("CaptchaElement", "audio") + '" title="' + LC.getLabel("CaptchaElement", "audio") + '" onclick="Recaptcha.switch_type(\'audio\')">');
        	html.push('          <img class="recaptcha_only_if_audio" src="' + UserContext.getUrl("/img/recaptcha_text.gif") + '" alt="' + LC.getLabel("CaptchaElement", "image") + '" title="' + LC.getLabel("CaptchaElement", "text") + '" onclick="Recaptcha.switch_type(\'image\')">');
            if (helpHref != null && helpHref.length > 0) {
            	html.push('          <img src="' + UserContext.getUrl("/img/recaptcha_help.gif") + '" alt="' + LC.getLabel("Buttons", "help") + '" title="' + LC.getLabel("Buttons", "help") + '" onclick="' + helpHref + '">');
            }
        	html.push('      </td>');
        	html.push('  </tr>');
        	html.push('  <tr><td colspan="2" style="border:0px">');
        	Captcha.dialog.createButtons(html);
        	html.push('<a id="moreinfo" style="float:right" href="#" onclick="Captcha.toggleMoreinfo(true)">');html.push(LC.getLabel("CaptchaElement", "moreinfo"));html.push('</a>');
        	html.push('  </td></tr>');
        	html.push('  <tr><td colspan="2" style="border:0px">');
        	html.push('    <div id="about" style="display:none"><img src="img/reCAPTCHAlogo.png" style="float:left;padding-right:5px">');
        	html.push('      <div style="font-size:85%">Security test provided by <a href="http://www.recaptcha.net" target="_blank">reCAPTCHA&trade;</a>');
        	html.push('      <br>The words above come from scanned books.  By typing them, you help to digitize old texts.</div>');
        	html.push('      <a style="float:right" href="#" onclick="Captcha.toggleMoreinfo(false)">');html.push(LC.getLabel("CaptchaElement", "lessinfo"));html.push('</a>');
        	html.push('    </div>');
        	html.push('  </td></tr>');
        	
        	html.push('</table>');
        	html.push('</div>');
        	
        	Captcha.dialog.setContentInnerHTML(html.join(""));
    	}
    	Captcha.dialog.show();
    	
        Captcha.displayOnly();
    },
    
    toggleMoreinfo : function(show) {
    	if (show) {
            document.getElementById('about').style.display = 'block';
            document.getElementById('moreinfo').style.display = 'none';
    	} else {
            document.getElementById('about').style.display = 'none';
            document.getElementById('moreinfo').style.display = 'inline';
    	}
    },
    
    displayOnly : function() {
        Recaptcha.create(Captcha.publicKey, null,
            { callback: Recaptcha.focus_response_field,
              theme: 'custom',
              lang: Captcha.recaptchaLang });
    },
    
    hide : function() {
        Captcha.dialog.hide();
    },

    // handles Captcha form submit
    submit : function() {
        if (!Captcha.checkRecaptchaConnected()) {
            Captcha.submitClientError();
        } else {
            Captcha.verify();
        }
        return false;
    },

    verify : function() {
        var challenge = Recaptcha.get_challenge();
        var response = Recaptcha.get_response();
        Recaptcha.destroy();
        Captcha.callVerifier(challenge, response, "false", Captcha.verifyResultCallback);
    },
    
    verifyResultCallback : function(response) {
        var responseText = response.responseText;
        var json = Util.evalAjaxServletOutput(responseText);
        if (json[CaptchaVerifierServlet.VALID_KEY] == true) {
            // proceed with the submit, which will now work
            Captcha.verified = true;
            Captcha.hide();
            Captcha.proceed();
        } else {
            // On failure, re-display the captcha
            document.getElementById('incorrect').style.display = 'block';
            Captcha.displayOnly();
        }
    },
    
    proceed : function() {
        if (Captcha.formName) {
	        document.forms[Captcha.formName][Captcha.submitButtonName].click();
    	} else {   
    	    window.location = document.getElementById(Captcha.submitButtonName).href;
    	}
    },
    
    submitClientError : function() {
        Captcha.callVerifier("", "", "true", Captcha.proceed);
    },
    
    callVerifier : function(chal, resp, clientError, callback) {
        var params = { };
        params[CaptchaVerifierServlet.CHALLENGE_PARAM] = chal;
        params[CaptchaVerifierServlet.RESPONSE_PARAM] = resp;
        params[CaptchaVerifierServlet.CLIENT_ERROR_PARAM] = clientError;
        var ajaxServletUrl = UrlMap.convertClassNameToUrl(CaptchaVerifierServlet.SERVLET_NAME, null);
        XBrowser.postHttpResponse(ajaxServletUrl, callback, XBrowser.buildPost(params));
    },
    
    checkRecaptchaConnected : function() {
        var imageHtml = document.getElementById('recaptcha_image').innerHTML;
        return !!imageHtml;
    }
}

/**
  A select element with the up & down arrows next to it.

  @author polcari
  @since 144

*/
function VerticallyArrangableSelectElement(_id) {
  this.id = _id;
  var vaSelectElement = this;
  sfdcPage.appendToOnloadQueue(function() {vaSelectElement.init()});
}

VerticallyArrangableSelectElement.prototype.init = function() {
  var containingNode = document.getElementById(this.id).parentNode.parentNode;
   //find the up & down buttons & attach to them
  var imgs = containingNode.getElementsByTagName("img");

  var _id = this.id;
  for (var i=0; (imgs && (i < imgs.length)); i++) {
    if (hasStyleClass(imgs[i], vaSelectElementConst.UP_CLASS)) {
      addEvent(imgs[i], 'click', function() {moveUp(document.getElementById(_id))}, false);
    } else if (hasStyleClass(imgs[i], vaSelectElementConst.DOWN_CLASS)) {
      addEvent(imgs[i], 'click', function() {moveDown(document.getElementById(_id))}, false);
    }
  }
}

function SearchQueryTool(targetEntityInputId) {
	this.queryTypeWithEntityStorage = new Object();
	this.targetEntityInputId = targetEntityInputId;
	this.entityInput = null;
	this.savedValue = null;
}

SearchQueryTool.prototype.addQueryTypeWithEntity = function (queryType){
	this.queryTypeWithEntityStorage[queryType] = queryType;
}

SearchQueryTool.prototype.processTargetEntity = function (queryType){
	if(!this.entityInput && !this.targetEntityInputId){ return; }
	
	// initialize lazily
	if (!this.entityInput){ 
		this.entityInput = document.getElementById(this.targetEntityInputId);
		this.targetEntityInputId = null;
	}
	
	if (queryType in this.queryTypeWithEntityStorage){
		this.entityInput.disabled = true;
		this.savedValue = this.entityInput.value;
		this.entityInput.value = '';
	} else {
		this.entityInput.disabled = false;
		if(this.savedValue){
			this.entityInput.value = this.savedValue;
		}
	}
}
/**
 * Simplified version of hash map
 * undefined value is not allowed, null or undefined key is not allowed
 * feel free to enhance it
 */
function Map() {
	this.size = 0;
	this.map = new Object();
}

Map.prototype.put = function (key, val) {
	// key not null or undefined, value is not undefined
	if (!key || typeof(val) == 'undefined' ) {
		return;
	}
	if (!(key in this.map)) {
		this.size++;
	}
	this.map[key] = val;
}

Map.prototype.remove = function (key) {
	if (key in this.map) {
		delete(this.map[key]);
		this.size--;
	}
}
/**
 * JS code to handle filtering in a ShareRuleSelectFilterElement.
 */
var ShareRuleSelectFilterElement = function(){
}

// filtering the drop-down based on the controller is really just showing
// the right corresponding drop-down and hiding the others.
ShareRuleSelectFilterElement.prototype.filterDropdown = function(name, map, currTypeSelect) {
    var selected = currTypeSelect.selectedIndex;
    var selectedMappedOption = this.getMappedOption(selected, map, currTypeSelect);
    for (var i = 0; i < currTypeSelect.options.length; i++){
        var mappedOption = this.getMappedOption(i, map, currTypeSelect);
        var optionList = name + '_' + mappedOption;
        var currSelect = document.getElementById(optionList);
        if (currSelect) {
        	if (mappedOption == selectedMappedOption) {
		        if (i == selected){
		            currSelect.style.display = 'inline';
		        }
		    } else {
	            currSelect.style.display = 'none';
	        }
        }
    }
}

ShareRuleSelectFilterElement.prototype.getMappedOption = function(index, map, currTypeSelect) {
	var option = currTypeSelect.options[index].value;
    var mappedOption = map[option];
    if (!mappedOption) {
       	mappedOption = option;
    }
    return mappedOption;
}
/**
 * OverlayDialog creates a modal or non-modal dialog in a div overlay.
 *
 * @author jmooney
 * @since 150
 */

function OverlayDialog() {
    this.id = null;
    this.dialog = null; // to hold the div element once it has been created
    this.isModal = true;
    this.extraClass = "";
    this.background = null; // create the background lazily
    this.width = OverlayDialog.MAX_WIDTH;
    this.minHeight = OverlayDialog.MIN_HEIGHT;
    this.minWidth = OverlayDialog.MIN_WIDTH;
    this.buttons = [];
    // setup default buttons
    this.title = null;
    this.header = null;
    this.info = null;
    this.isOpen = false;
    this.created = false;
    this.displayX = true;
    this.isResizable = false;
    this.isMovable = false;
    this.positioned = false;
    this.moving = false;
    this.resizing = false;
    this.fixedX = 0;
    this.fixedY = 0;
    this.relativeX = 0;
    this.relativeY = 0;
    this.changeX = 0;
    this.changeY = 0;
}

OverlayDialog.prototype.addEvents = function() {
    var self = this;
    addEvent(document, "keydown", function(e) { self.handleKeyPress(e); }, false);
    addEvent(window, "resize", function() { self.resizeEvent(); }, false);
    if (XBrowser.userAgent.isIE6) {
        addEvent(window, "scroll", function() { self.scrollEvent(); }, false);
    }
}

OverlayDialog.prototype.setTitle = function(title) {
    this.title = title;
    if (this.created) {
        document.getElementById(this.id + "Title").innerHTML = this.title;
    }
}

OverlayDialog.prototype.setHeader = function(header) {
    this.header = header;
    if (this.created) {
        document.getElementById(this.id + "Header").innerHTML = this.header;
    }
}

OverlayDialog.prototype.setInfo = function(info) {
    this.info = info;
    if (this.created) {
        document.getElementById(this.id + "Info").innerHTML = this.info;
    }
}

OverlayDialog.prototype.setWidth = function(width) {
    this.width = width;
    if (this.created) {
        if (typeof width == "string") {
            this.dialog.style.width = width;
        } else {
            this.dialog.style.width = width + "px";
        }
        if (this.isOpen) {
            this.position();
        }
    }
}

// the minimum height allowed when resizing
OverlayDialog.prototype.setMinHeight = function(minHeight) {
    this.minHeight = minHeight;
}

// the minimum width allowed when resizing
OverlayDialog.prototype.setMinWidth = function(minWidth) {
    this.minWidth = minWidth;
}

/**
 * by default, button 0 is Ok, 1 is cancel, 2 is null.
 * Override a button with a different label and a function that should be called when the button is pressed.
 * The function passed in can either be a function reference or just a string. The function should return
 * true if the dialog should hide itself, false if it should stay open.
 * Example:
 *
 * function verifySave() {...}
 * dialog.overrideButton(0, "Save", checkSave);
 * -OR-
 * dialog.overrideButton(0, "Save", "checkSave()");
 *
 * using a string you can actually pass in jsut an expression:
 * dialog.overrideButton(2, "Special", "checkSave() && something > 15");
 *
 */
OverlayDialog.prototype.overrideButton = function(index, disp, fn) {
    if (index >= OverlayDialog.MAX_BUTTONS) {
        throw "Cannot have more than " + OverlayDialog.MAX_BUTTONS + " buttons.";
    }
    this.buttons[index] = { display: disp, action: fn };
}

OverlayDialog.prototype.setupDefaultButtons = function() {
    this.buttons = [];
    this.buttons[0] = { display: LC.getLabel("Buttons", "ok"), action: null };
    this.buttons[1] = { display: LC.getLabel("Buttons", "cancel"), action: null };
}

/**
 * Remove all action buttons from the dialog (the ones at the bottom).
 */
OverlayDialog.prototype.clearButtons = function() {
    this.buttons = [];
}

// constants
OverlayDialog.MAX_BUTTONS = 4;
OverlayDialog.MAX_WIDTH = 800;
OverlayDialog.MIN_WIDTH = 300;
OverlayDialog.MIN_HEIGHT = 200;
OverlayDialog.EDGE_BUFFER = 40;

OverlayDialog.prototype.show = function() {
    this.dialog.style.display = "block";
    this.position();
    if (this.isModal) {
        if (!this.background) {
            this.createBackground();
        }
        this.background.style.display = "block";
        // have to hide all selects, even an iframeshim causes flickering
        if (XBrowser.userAgent.isIE6) {
            var allSelects = document.getElementsByTagName("select");
            var dialogSelects = this.dialog.getElementsByTagName("select");
            var allLength = allSelects.length;
            var dialogLength = dialogSelects.length;
            for (var i = 0; i < allLength; i++) {
                // could save the old values but nobody ever uses visibility on selects
                allSelects[i].style.visibility = "hidden";
            }
            for (var i = 0; i < dialogLength; i++) {
                // could save the old values but nobody ever uses visibility on selects
                dialogSelects[i].style.visibility = "visible";
            }
        }
    }
    this.dialog.style.visibility = "visible";
    this.isOpen = true;
}

OverlayDialog.prototype.hide = function() {
    if (this.isMovable) {
        this.stopDrag();
    }
    if (this.isModal) {
        this.background.style.display = "none";
        if (XBrowser.userAgent.isIE6) {
            var allSelects = document.getElementsByTagName("select");
            var allLength = allSelects.length;
            for (var i = 0; i < allLength; i++) {
                // could save the old values but nobody ever uses visibility on selects
                allSelects[i].style.visibility = "visible";
            }
        }
    }
    this.dialog.style.visibility = "hidden";
    this.dialog.style.display = "none";
    this.isOpen = false;
}

/**
 * called when clicking on the X or pressing esc to get out of the dialog
 */
OverlayDialog.prototype.cancel = function() {
    this.hide();
}

OverlayDialog.prototype.handleKeyPress = function(e) {
    if (this.isOpen) {
        e = getEvent(e);
        var key = e.keyCode;
        if (key == KEY_ESC) {
            this.cancel();
        } else if (key == KEY_ENTER && this.captureEnter(getEventTarget(e))) {
            this.enter();
        }
    }
}

// don't capture enter event from links, buttons, or textareas
OverlayDialog.prototype.captureEnter = function(target) {
    return target.nodeName != "A" && target.nodeName != "TEXTAREA" && target.type != "button";
}

OverlayDialog.prototype.enter = function() {
    // does nothing by default
}

OverlayDialog.prototype.position = function() {
    if (this.resizing) {
        var width = this.startWidth + this.changeX;
        var height = this.startHeight + this.changeY;
        if (width < this.minWidth) {
            width = this.minWidth;
        }
        if (height < this.minHeight) {
            height = this.minHeight;
        }
        this.dialog.style.width = width + "px";
        this.dialog.style.height = height + "px";
        var inner = document.getElementById(this.getContentId());
        // subtract size of top/bottom bars
        inner.style.height = (height - 46) + "px";
    } else {
        // all dialogs still get centered the first time
        if (!this.positioned) {
            this.setInnerHeight();
            var left = getWindowWidth() - this.dialog.offsetWidth;
            left = left < 6 ? 6 : left / 2;
            var top = getWindowHeight() - this.dialog.offsetHeight;
            top = top < 6 ? 6 : top / 2;
            this.fixedX = left;
            this.fixedY = top;
        } else {
            // check for viewport overflow, from dragging off the screen or resize
            var maxX = getWindowWidth() - OverlayDialog.EDGE_BUFFER;
            var maxY = getWindowHeight() - OverlayDialog.EDGE_BUFFER;
            var minX = OverlayDialog.EDGE_BUFFER - this.dialog.offsetWidth;
            var minY = OverlayDialog.EDGE_BUFFER / 2;
            if (this.fixedX < minX) {
                this.fixedX = minX;
            } else if (this.fixedX > maxX) {
                this.fixedX = maxX;
            }
            if (this.fixedY < minY) {
                this.fixedY = OverlayDialog.EDGE_BUFFER;
            } else if (this.fixedY > maxY) {
                this.fixedY = maxY;
            }
        }
        if (XBrowser.userAgent.isIE6) {
            this.dialog.style.left = (this.fixedX + getScrollX()) + "px";
            this.dialog.style.top = (this.fixedY + getScrollY()) + "px";
        } else {
            this.dialog.style.left = this.fixedX + "px";
            this.dialog.style.top = this.fixedY + "px";
        }
    }
}

OverlayDialog.prototype.setInnerHeight = function() { }

OverlayDialog.prototype.createBackground = function() {
    this.background = document.createElement("div");
    this.background.className = "overlayBackground";
    if (this.dialog.currentStyle && XBrowser.userAgent.isIE6) {
        this.background.style.width = document.body.offsetWidth + "px";
        this.background.style.height = document.body.offsetHeight + "px";
    } else {
        this.background.style.width = document.documentElement.scrollWidth + "px";
        this.background.style.height = document.documentElement.scrollHeight + "px";
    }
    document.body.appendChild(this.background);
    var self = this;
    addEvent(this.background, "mousedown", function(e) { self.smash(e); }, false);
    addEvent(this.background, "click", function(e) { self.smash(e); }, false);
}

OverlayDialog.prototype.scrollEvent = function() {
    // this is only called for IE6
    if (this.created) {
        this.position();
    }
}

OverlayDialog.prototype.resizeEvent = function() {
    if (this.created) {
        if (this.background) {
            if (this.background.currentStyle && XBrowser.userAgent.isIE6) {
                this.background.style.width = document.body.offsetWidth + "px";
                this.background.style.height = document.body.offsetHeight + "px";
            } else {
                this.background.style.width = document.documentElement.scrollWidth + "px";
                this.background.style.height = document.documentElement.scrollHeight + "px";
            }
        }
        this.position();
    }
}

OverlayDialog.prototype.createDialog = function() {
    var div = document.createElement("div");
    div.id = this.id;
    div.className = "overlayDialog " + this.extraClass;
    if (typeof this.width == "string") {
        div.style.width = this.width;
    } else if (typeof this.width == "number") {
        div.style.width = this.width + "px";
    }
    var html = [];
    html.push("<div class='topRight");
    if (this.isMovable) {
        html.push(" movable");
    }
    html.push("'><div class='topLeft'>");
    if (this.displayX) {
        html.push("<img id='");
        html.push(this.id);
        html.push("X' onmouseover=\"this.className = 'dialogCloseOn'\" onmouseout=\"this.className = 'dialogClose'\" onclick=\"sfdcPage.getDialogById('");
        html.push(this.id);
        html.push("').cancel()\" class='dialogClose' src='" + UserContext.getUrl('/s.gif') + "'>");
    }
    html.push("<h2 id='");
    html.push(this.id);
    html.push("Title'>");
    html.push(this.title);
    html.push("</h2></div></div><div class='middle'><div class='innerContent' id='");
    html.push(this.getContentId());
    html.push("'></div></div>");
    if (this.isResizable) {
        html.push("<div id='");
        html.push(this.id);
        html.push("Resize' class='dialogResize'></div>");
    }
    html.push("<div class='bottomRight'><div class='bottomLeft'></div></div>");
    div.innerHTML = html.join("");
    document.body.appendChild(div);
    this.dialog = div;
    var self = this;
    if (this.isMovable || this.isResizable) {
        addEvent(document, "mouseup", function() { self.stopDrag(); }, false);
        if (this.isMovable) {
            var dragger = this.dialog.firstChild;
            addEvent(dragger, "mousedown", function(e) { self.startMove(e); }, false);
            addEvent(document, "mousemove", function(e) { self.move(e); }, false);
        }
        if (this.isResizable) {
            var resizer = document.getElementById(this.id + "Resize");
            addEvent(resizer, "mousedown", function(e) { self.startResize(e); }, false);
            addEvent(document, "mousemove", function(e) { self.resize(e); }, false);
        }
    }
    this.createContent();
    this.created = true;
}

OverlayDialog.prototype.createContent = function() { }

OverlayDialog.prototype.startMove = function(e) {
    e = getEvent(e);
    var target = getEventTarget(e);
    // don't drag from the X
    if (target.nodeName != "IMG") {
        this.positioned = true;
        this.moving = true;
        this.relativeX = e.clientX - this.dialog.offsetLeft;
        this.relativeY = e.clientY - this.dialog.offsetTop;
        if (XBrowser.userAgent.isIE6) {
            this.relativeX += getScrollX();
            this.relativeY += getScrollY();
        }
        this.fixedX = e.clientX - this.relativeX;
        this.fixedY = e.clientY - this.relativeY;
        this.smash(e);
    }
}

OverlayDialog.prototype.startResize = function(e) {
    e = getEvent(e);
    this.positioned = true;
    this.resizing = true;
    this.relativeX = e.clientX;
    this.relativeY = e.clientY;
    this.startWidth = this.dialog.offsetWidth;
    this.startHeight = this.dialog.offsetHeight;
    this.smash(e);
}

OverlayDialog.prototype.stopDrag = function() {
    this.moving = false;
    this.resizing = false;
}

OverlayDialog.prototype.move = function(e) {
    if (this.moving) {
        e = getEvent(e);
        this.smash(e);
        this.fixedX = e.clientX - this.relativeX;
        this.fixedY = e.clientY - this.relativeY;
        this.position();
    }
}

OverlayDialog.prototype.resize = function(e) {
    if (this.resizing) {
        e = getEvent(e);
        this.smash(e);
        this.changeX = e.clientX - this.relativeX;
        this.changeY = e.clientY - this.relativeY;
        this.position();
    }
}

OverlayDialog.prototype.smash = function(e) {
    if (e.stopPropagation) {
        e.stopPropagation();
    } else {
        e.cancelBubble = true;
    }
    if (e.preventDefault) {
        e.preventDefault();
    } else {
        e.returnValue = false;
    }
}

OverlayDialog.prototype.getContentId = function() {
    return this.id + "Content";
}

OverlayDialog.prototype.createButtons = function(html) {
    html.push("<div class='buttons'>");
    for (var i = 0; i < this.buttons.length; i++) {
        var display = this.buttons[i].display;
        var action = this.buttons[i].action;
        html.push("<input class='btn' type='button' value='");
        html.push(display);
        html.push("' onclick=\"");
        if (typeof action == "string") {
            html.push("if(");
            html.push(action.replace(/"/, "\\\""));
            html.push(")");
        } else if (typeof action == "function") {
            html.push("if(");
            html.push(action.name);
            html.push("())");
        }
        html.push("sfdcPage.getDialogById('");
        html.push(this.id);
        html.push("').hide();\">");
    }
    html.push("</div>");
}

OverlayDialog.prototype.register = function() {
    sfdcPage.registerDialog(this);
}


/**
 * Functions for Email Template Preview page
 * @author ccopek
 * @since 156
 */

function EmailTemplatePreview() {}

/**
 * Depending on the option selected (Lookup or ID), the associated input fields
 * for the option will be enabled/disabled and marked required/not required.
 */
EmailTemplatePreview.prototype.toggleRctOptions = function(typePrefix, lookupPrefix) {
    var lookupOption = document.getElementById(typePrefix+'Option0');
    var idInput = document.getElementById(typePrefix+'Id');
    var lookupInput = document.getElementById(lookupPrefix);
    var lookupLink = document.getElementById(lookupPrefix+LookupInputElement.pLOOKUP_WIDGET);
    var lookupRequiredBlockDiv = document.getElementById(typePrefix+EmailTemplatePreviewConstants.LOOKUP_REQUIRED_BLOCK_ID);
    var idRequiredBlockDiv = document.getElementById(typePrefix+EmailTemplatePreviewConstants.ID_REQUIRED_BLOCK_ID);

    if (lookupOption.checked) {
        // Lookup option was selected.
        // disable the id input field and remove required bar
        idInput.disabled = true;
        idRequiredBlockDiv.className = '';

        // enable the lookup related elements and add required bar
        lookupInput.disabled = false;
        lookupLink.disabled = false;
        lookupRequiredBlockDiv.className = EmailTemplatePreviewConstants.REQUIRED_BLOCK_CLASS;
    } else {
        // Id option was selected.
        // enable the id input field and add required bar
        idInput.disabled = false;
        idRequiredBlockDiv.className = EmailTemplatePreviewConstants.REQUIRED_BLOCK_CLASS;

        // disable the lookup related elements and remove required bar
        lookupInput.disabled = true;
        lookupLink.disabled = true;
        lookupRequiredBlockDiv.className = '';
    }
}

/**
  JS code for attaching events for CompactLayoutUi.

  @author polcari
  @since 144
*/
function CompactLayoutUi(_unusedItems, _leftColItems, _rightColItems) {
  var clUi = this;
  this.appendToOnloadQueue(function() {clUi.attachEvents();});
}

CompactLayoutUi.prototype = new GenericSfdcPage();

CompactLayoutUi.prototype.initialize = function(_unusedItems, _leftColItems, _rightColItems) {
  this.unusedItems = _unusedItems;
  this.leftColItems = _leftColItems;
  this.rightColItems = _rightColItems;
}

CompactLayoutUi.prototype.attachEvents = function() {
  var unusedSelectBox = document.getElementById(this.unusedItems);
  var leftColBox = document.getElementById(this.leftColItems);
  var rightColBox = document.getElementById(this.rightColItems);

  var clUi = this;

  //attach the events to the images on the page
  //TODO: polcari - 146: this should be done declaratively in GenericSfdcPage....  Each subclass returns a list of ids, handlers, functions & 'captures'
  //						"elements" should also implement this declarative event-attaching method - rather than id's, they are attached via classname (since there can be multiple elements per page).
  //                        These elements must have an id, because we can't hunt through the DOM for looking for classnames
  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.switchColumnToRight), function() {moveOption(leftColBox, rightColBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});
  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.switchColumnToLeft), function() {moveOption(rightColBox, leftColBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});

  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.hideItemsLeft), function() {moveOption(leftColBox, unusedSelectBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});
  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.showItemsLeft), function() {moveOption(unusedSelectBox, leftColBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});

  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.hideItemsRight), function() {moveOption(rightColBox, unusedSelectBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});
  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.showItemsRight), function() {moveOption(unusedSelectBox, rightColBox, LC.getLabel("SelectElement", "Required"), [], null, LC.getLabel("SelectElement", "Required"));});

  CompactLayoutUi.addClick(document.getElementById(CompactLayoutUiConst.saveButtonId), function() {clUi.selectAll(); return true;});
}

CompactLayoutUi.prototype.selectAll = function () {
  var leftColBox = document.getElementById(this.leftColItems);
  var rightColBox = document.getElementById(this.rightColItems);

  for(var i = 0;i < leftColBox.length;i++) { leftColBox.options[i].selected=true; }
  for(var i = 0;i < rightColBox.length;i++) { rightColBox.options[i].selected=true; }
}

//Convenience function to save typing
CompactLayoutUi.addClick = function(elem, fn) {
  addEvent(elem, 'click', fn, false);
}

    /** @author zzhou
     *  @since 150
     * Used for ForecastRoleUserPage to enable/disable the Forecast Share options for a FM */

	function ForecastRoleUser() {};
    ForecastRoleUser.checkDisplayAllowSharing = function() {
        var selectedElement = document.getElementById(ForecastRoleUser.pUSER)
        //if no user is selected, we hide the Forecast Sharing div and disable the checkboxes
        if (selectedElement.options[selectedElement.selectedIndex].value == '') {
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[0].disabled=true;
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[1].disabled=true;
            document.getElementById(ForecastRoleUser.FORECAST_SHARE_RADIO).style.visibility = 'hidden';
        } else {
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[0].disabled=false;
            document.getElementsByName(ForecastRoleUser.pCAN_SHARE)[1].disabled=false;
            document.getElementById(ForecastRoleUser.FORECAST_SHARE_RADIO).style.visibility = 'visible';
        }
    }

    //confirm fct share removal
    ForecastRoleUser.confirmRemoveShares = function(hadMgr) {
        var selectedElement = document.getElementById(ForecastRoleUser.pUSER);
        return selectedElement.options[selectedElement.selectedIndex].value != '' || !hadMgr || window.confirm(LC.getLabel("ForecastSharingPref","confirmAssignNoMgr"));
    }
SfdcElement = function() {};

SfdcElement.prototype.getElements = function(ids) {
    var elements = [];
    for (var n = 0; n < ids.length; n++) {
         elements.push(document.getElementById(ids[n]))
    }
    return elements;
}

SfdcElement.prototype.setVisibleElementsById = function(ids, show) {
    SfdcElement.prototype.setVisibleElements(SfdcElement.prototype.getElements(ids), show);
}

SfdcElement.prototype.setVisibleElements = function(elements, show) {
    for (var n = 0; n < elements.length; n++) {
        elements[n].style.visibility = (show) ? 'visible' : 'hidden'
    }
}

SfdcElement.prototype.setDisplayElementsById = function(ids, display) {
    SfdcElement.prototype.setDisplayElements(SfdcElement.prototype.getElements(ids), display);
}

SfdcElement.prototype.setDisplayElements = function(elements, display) {
    for (var n = 0; n < elements.length; n++) {
        elements[n].style.display = (display) ? 'block' : 'none'
    }
}

SfdcElement.prototype.setDisabledById = function(ids, disabled){
    SfdcElement.prototype.setDisabled(SfdcElement.prototype.getElements(ids), disabled);
}

SfdcElement.prototype.setDisabled = function(elements, disabled){
    for (var n = 0; n < elements.length; n++) {
        elements[n].disabled = disabled;
    }
}


function BrowserSettingsWarning() {
	var warning = this;
	if (window.sfdcPage) {
		window.sfdcPage.appendToOnloadQueue(function() {warning.init();});
	}
}
		
BrowserSettingsWarning.DO_NOT_ASK_AGAIN_EXPIRY = 60; // 2 months

BrowserSettingsWarning.prototype.init = function() {
	var browserSettingsWarning = this;
	var neverAgain = document.getElementById(BrowserSettingsWarningElement.NEVER_SHOW_AGAIN_ID);
	addEvent(neverAgain, "click" , function(e) {
		 browserSettingsWarning.neverShowAgain(); 
		 return false;
		 }, false);
	var moreInfo =  document.getElementById(BrowserSettingsWarningElement.MORE_INFO_ID);
	addEvent(moreInfo, "click" , function(e) {
		 Cookies.prototype.SetCookie(BrowserSettingsWarningElement.cBrowserSettings, "0", new Date(), "/");
		 browserSettingsWarning.hideElement(); 
		 }, false);
}

BrowserSettingsWarning.prototype.neverShowAgain = function() {
	var expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + BrowserSettingsWarning.DO_NOT_ASK_AGAIN_EXPIRY);
						//	name, value, expires, path, domain
	Cookies.prototype.DeleteCookie(BrowserSettingsWarningElement.cBrowserSettings);
	Cookies.prototype.SetCookie(BrowserSettingsWarningElement.cBrowserSettings, "-1", expiryDate, "/");
	this.hideElement();
}

BrowserSettingsWarning.prototype.hideElement = function() {
	document.getElementById(BrowserSettingsWarningElement.BROWSER_SETTINGS_WARNING_ID).style.display = 'none';
}
/**
  CustomMotifDefinition is instantiated on (you guessed it) CustomMotifDefinitionPage.java

  @author polcari
  @since 144


  @parentMotifId  This id for the parent's motifElement.  It is passed as a QS var to CustomMotifDefinitionPage

*/

function CustomMotifDefinition(parentMotifId) {

  this.parentMotifInputObject = window.opener.document.getElementById(parentMotifId).motifInputElement;
  this.motifObject = document.getElementById(CustomMotifDefinitionPageConst.COLOR_ELEMENT).motifInputElement;
  this.iconObject = document.getElementById(CustomMotifDefinitionPageConst.MOTIF_ICON_PARAM).imageSelectElement;
}


//this has dependancies on a number of global JS vars
//see CustomMotifDefinitionPage.getVariablesForJS()
CustomMotifDefinition.prototype.returnSelections = function() {
  if (this.motifObject.isNull()) {
    alert(noMotifErrorMsg);  //It would be nice to load these from LC
    return false;
  } else if (this.iconObject.isNull()) {
    alert(noIconErrorMsg);
    return false;
  } else {
   //copy Motif key
    this.parentMotifInputObject.motifElement.className = this.motifObject.motifElement.className.replace("motifColorElement","customDefinedMotif");
    this.parentMotifInputObject.setMotifKey(this.motifObject.motifKeyInput.value);
   //copy text
    this.parentMotifInputObject.setDescription(userDefinedDescription);
   //copy image
    this.parentMotifInputObject.setIconSrc(this.iconObject.image.src);
    this.parentMotifInputObject.setIconValue(this.iconObject.inputElement.value);

    window.blur();
    window.close();
    return true;
  }
}


//helper function
CustomMotifDefinition.prototype.copyInputVal = function(fromID, toID) {
  window.opener.document.getElementById(toID).value = document.getElementById(fromID).value;
}
//helper function
CustomMotifDefinition.prototype.copyInput = function(fromInput, toInput) {
  toInput.value = fromInput.value;
}



/**
 * @author zzhou
 * since 148
 * CrtLayout Available Section javascript code; also see CrtLayout.js, AvailableField.js, Lookups.js
 */


CrtLayoutElement.availableSections = {};

AvailableSection.prototype.addField = function(availField) {
    this.fields[availField.id] = availField;
}

//theorically it will make more sense to attach event handlers to the individual field element themselves
//however setting all the event handlers on each of the fields would take too long on a page with many fields
//thus we attach events to the parent element and then delegate to the appropriate event handler during events
AvailableSection.prototype.attachEvents = function(pageNum) {
    var self = this;
    var tableElem = document.getElementById(self.getPagenationId(self.sectionId,pageNum));
    addEvent(tableElem, 'mouseover', function(evt) {self.handleMouseOver(evt);}, false);
    addEvent(tableElem, 'mouseout', function(evt) {self.handleMouseOut(evt);}, false);
    addEvent(tableElem, 'mousedown', function(evt) {self.handleMouseDown(evt);}, false);
    addEvent(tableElem, 'click', function(evt) {self.handleMouseClick(evt);}, false);

}

AvailableSection.prototype.handleMouseOver = function(evt) {
    var elem = getEventTarget(evt);
    var field = this.fields[elem.id];
    if (field) {
        if (!field.elem) {
            field.elem = elem;
        }
        field.handleMouseOver(evt);
        return;
    }

    if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove) {
        //swap to appropriate section based on the currentSelectedObj
        CrtLayoutElement.clearHighlights();
        var fieldValue = MoveableItem.currentSelectedObj.itemId;
        var sectionObj = CrtLayoutElement.getSectionFromFieldValue(fieldValue);
        sectionObj.highlightSection(fieldValue);
    } else {
        CrtLayoutElement.handleMouseOver(evt);
    }
}

AvailableSection.prototype.handleMouseOut = function(evt) {
    var elem = getEventTarget(evt);
    var field = this.fields[elem.id];
    if (field) {
        if (!field.elem) {
            field.elem = elem;
        }
        field.handleMouseOut(evt);
    }
}

AvailableSection.prototype.handleMouseDown = function(evt) {
    var elem = getEventTarget(evt);
    var field = this.fields[elem.id];
    if (field) {
        if (!field.elem) {
            field.elem = elem;
        }
        field.handleMouseDown(evt);
        return;
    }
}

AvailableSection.prototype.handleMouseClick = function(evt) {
    var elem = getEventTarget(evt);
    var field = this.fields[elem.id];
    if (field) {
        if (!field.elem) {
            field.elem = elem;
        }
        field.handleMouseClick(evt);
        return;
    }
}

CrtLookupSection.getSectionIdFromPrim = function(primaryObjId) {
    return primaryObjId + '_' + LookupsUi.LOOKUPS;
}

AvailableSection.prototype.highlightSection = function(fieldValue) {
    var pageNum = this.fields[fieldValue].pageNum;
    this.swapToSectionDiv(null,pageNum);
    var sectionObj = document.getElementById(this.getPagenationId(this.sectionId,pageNum));
    sectionObj.className = sectionObj.className + ' lookupHighlightSection';
    CrtLayoutElement.highlightAvailSection = this;
}

AvailableSection.prototype.handleMouseUp = function(evt) {
    var sectionObj = document.getElementById(this.getPagenationId(this.sectionId,this.currentPage));
    sectionObj.className = "availSectionTable";
    CrtLayoutElement.highlightAvailSection = null;
}

function AvailableSection(sectionId, divId, headerTitle) {
        this.sectionId = sectionId;
        this.divId = divId;
        this.sectionHeaderId = this.sectionId+'_HEADER';
        this.sectionFooterId = this.sectionId+'_FOOTER';
        this.currentPage = 1;
        this.headerTitle = headerTitle;
        //avail fields
        this.fields = {};

        //add section to map of all LookupSections;
        CrtLayoutElement.availableSections[this.sectionId] = this;
 }

//extend Available Section to CrtLookupSection
CrtLookupSection.prototype = new AvailableSection();

 function CrtLookupSection(sectionId, divId, headerTitle) {
        this.sectionId = sectionId;
        this.divId = divId;
        this.sectionHeaderId = this.sectionId+'_HEADER';
        this.sectionFooterId = this.sectionId+'_FOOTER';
        this.currentPage = 1;
        this.headerTitle = headerTitle;
        //avail fields
        this.fields = {};


    //add section to map of allLookupSections;
    CrtLayoutElement.availableSections[sectionId] = this;
}

AvailableSection.prototype.moveCells = function() {
           //first set the old positions to empty for all the cells being moved
         CrtLayoutElement.sectionsToReformat = {};
         for (var i=0; i < MoveableItem.selectedBucket.length; i++) {
                var item = MoveableItem.selectedBucket[i];
                 //cannot move available fields around
               if (item.inLayout) {
                  item.fieldObj.handleMoved();
                  if (this.fields[item.itemId]) {
                      this.fields[item.itemId].handleMoveTo();
                  }
                  //or else needs to move these fields to another section
                  else {
                      CrtLayoutElement.getSectionFromFieldValue(item.itemId).fields[item.itemId].handleMoveTo();
                  }
               }
         }
        CrtLayoutElement.reformatSections();
   }

//return the lookup fields in terms of a CrtFieldCollection
CrtLookupSection.prototype.getFieldCollection = function() {
    var lookups = new CrtFieldCollection();
    for (var i in this.fields) {
        var field = this.fields[i].getFieldValue();
        var iFieldSep = field.indexOf(CrtLayoutElement.FIELD_SEP);
        var iIdSep = field.indexOf(CrtLayoutElement.COL_SEP);
        var path = field.substring(0,iFieldSep);
        var fieldName = field.substring(iFieldSep+1,iIdSep);
        lookups.addField(path,fieldName);
    }
    return lookups;
}

CrtLookupSection.prototype.removeFieldCollection = function(removedFields) {
    var allFieldKeys = removedFields.getAllFieldKeys();
    for (var i=0; i<allFieldKeys.length; i++) {
        var crtFieldObj = removedFields.getField(allFieldKeys[i]);
        var colId = "";
        var stuff = CrtLayoutElement.initialStateColIdMap;
        if (CrtLayoutElement.initialStateColIdMap[crtFieldObj.objectPath+CrtLayoutElement.FIELD_SEP+crtFieldObj.field]) {
            colId = CrtLayoutElement.initialStateColIdMap[crtFieldObj.objectPath+CrtLayoutElement.FIELD_SEP+crtFieldObj.field];
        }
        var fieldValue = this.createFieldKey(crtFieldObj,colId);

        //remove fields from layout and reformat the table
        this.fields[fieldValue].removeFromLayout();
        delete this.fields[fieldValue];
    }

    //reformat tables
    CrtLayoutElement.reformatSections();
}

//add the drop down picklist for the lookupSection
CrtLookupSection.prototype.addPicklist = function(primObjDivId) {
    //select Element
    var selectedElement = document.getElementById(CrtLayoutElement.FIELD_TYPE_SELECT_NAME);

    //create the drop down list to select this lookup section div
    var newOpt = new Option(selectedElement.options[selectedElement.selectedIndex].text+ ' ' + LC.getLabel("CRTLookupLayer","viaLookupParen"), this.sectionId, false, false);
    Util.insertOption(selectedElement,newOpt,selectedElement.selectedIndex+1);
}

//remove the section by removing it from the document node tree;
//also remove the selected element
//also remove of it's fields from layout section
CrtLookupSection.prototype.remove = function() {
    //remove the option from the select picklist
    var selectedElement = document.getElementById(CrtLayoutElement.FIELD_TYPE_SELECT_NAME);
    //decide which one to remove
    if (selectedElement.options[selectedElement.selectedIndex].value == this.sectionId) {
        var selectInd = selectedElement.selectedIndex;
        selectedElement.options[selectedElement.selectedIndex]=null;
        selectedElement.options[selectInd-1].selected = true;
    } else {
        selectedElement.options[selectedElement.selectedIndex+1]=null;
    }

    CrtLayoutElement.swapAvailableType(selectedElement);

    //remove the element
    var divElem = document.getElementById(this.getPagenationId(this.divId,1));
    divElem.parentNode.removeChild(divElem);

    //remove all fields and reformat layout tables
    var tableId;
    for (var i in this.fields) {
        this.fields[i].removeFromLayout();
    }
    CrtLayoutElement.reformatSections();
}

//swap to the appropriate div and change the available section picklist
AvailableSection.prototype.swapToSectionDiv = function(fromPage,toPage) {
    //select Element
    var selectedElement = document.getElementById(CrtLayoutElement.FIELD_TYPE_SELECT_NAME);

    //select to the appropriate picklist value/section div if needed
    if (selectedElement.options[selectedElement.selectedIndex].value != this.sectionId) {
        for (var i=0; i< selectedElement.options.length; i++) {
            if (selectedElement.options[i].value == this.sectionId) {
                selectedElement.options[i].selected = true;
                break;
            }
        }

    }
    CrtLayoutElement.swapAvailableType(selectedElement,fromPage,toPage);

}


//SPECIAL function to move lookup fields initially to the layout sections
CrtLookupSection.prototype.moveFields = function(newFields) {
    //move it to the section with the appropriate name
    //TODO what happens if we have unique section names (with numbering)?
    var primObjId = CrtLayoutElement.getPrimObjId(this.divId,CrtLayoutElement.DIV_SEP);
    var secName = CrtLayoutElement.getPrimObjMetaMap()[primObjId].label;
    var map = CrtLayoutElement.sectionNameIdMap;
    var secObj = CrtLayoutElement.sectionNameIdMap[secName];
    if (!secObj) {
        //if we don't have section with that name, create the section and get its table again
        secObj = CrtLayoutElement.createNewSection(secName);
    }

    //add all newly added fields to the selected bucket and then try to insert them
    for (var i=0; i<newFields.length; i++) {
        newFields[i].addSelection();
    }
    //try to insert these cells now
    //move these cells to the end of the section
    secObj.moveCells(secObj.numRows-1,secObj.numCols-1);
    MoveableItem.clearSelectedItems();
}

AvailableSection.prototype.renderFields = function() {
    //only for lookups do we regenerate the divs if necessary
    if (this instanceof CrtLookupSection) {
        this.removeDivs();
    }

    var fieldsArray = [];
    for (var i in this.fields) {
           fieldsArray.push(this.fields[i]);
    }
    //do some paging-related calculations
    var numCols = fieldsArray.length > CrtLayoutElement.NUM_ROWS_PER_AVAILABLE_SECTION ? 2 : 1;
    this.numPages = Math.ceil(fieldsArray.length / (numCols * CrtLayoutElement.NUM_ROWS_PER_AVAILABLE_SECTION));

    var k=0;
    var innerHTML;
    //parent Node is just the parent of the primary obj div
    var parentNode = document.getElementById("tcForAvailableSections");
    for (var pageNum=1; pageNum <= this.numPages; pageNum++) {
        /*init html elements */
        //div element

        var lookupDivElem = document.createElement("div");
        lookupDivElem.id = this.getPagenationId(this.divId,pageNum);
        lookupDivElem.className = 'availFieldsSection';
        lookupDivElem.style.display = 'none';
        innerHTML = [];

        //table header div element
        innerHTML.push('<div id=\"' + this.getPagenationId(this.sectionHeaderId,pageNum) + '\" style=\"padding:4px;\">');

        //title is '<Object> fields'
        //var html = '';
        innerHTML.push('<div>' + this.headerTitle + ' <span class="availHeadPaging">[Page' + pageNum + '/' + this.numPages + ']</span></div>');

        innerHTML.push(this.addPagingDivs(pageNum));
        innerHTML.push('</div>');

        //main table element div
        innerHTML.push('<div class=\"lookupSectionTableDiv noFloat\">');

        //section table element
        innerHTML.push('<table id=\"' + this.getPagenationId(this.sectionId,pageNum) + '\" class=\"availLookupSectionTable\">');
        innerHTML.push('<tbody>');
        //insert cells for each lkup section table
        for (var j=0; j < CrtLayoutElement.NUM_ROWS_PER_AVAILABLE_SECTION && k < fieldsArray.length; j++) {
            innerHTML.push('<tr>')
            for (var l =0; l < numCols && k < fieldsArray.length; l++, k++) {
                //fix the pageNum of the field to it's actual section
                var field = fieldsArray[k];
                field.pageNum = pageNum;
                innerHTML.push('<td id=\"' + field.id + '\" class=\"availField ');
                innerHTML.push(field.inLayout ? 'usedAvailField' : 'unusedAvailField');
                innerHTML.push('\">' + field.formatDName() + '</td>');
            }
            innerHTML.push('</tr>');
        }
        innerHTML.push('</tbody></table></div>');

        innerHTML.push('<div id=\"' + this.getPagenationId(this.sectionFooterId,pageNum) + '\">');
        innerHTML.push(this.addPagingDivs(pageNum));

        //no float div
        innerHTML.push('</div>');
        innerHTML.push('<div class=\"noFloat\"></div>');

        lookupDivElem.innerHTML += innerHTML.join('');
        parentNode.appendChild(lookupDivElem);
        this.attachEvents(pageNum);
    }
}

AvailableSection.prototype.getPagenationId = function(id, pageNum) {
     return id+'_'+pageNum;
 }

CrtLookupSection.prototype.removeDivs = function() {
    //remove all pagenated divs
    for (var i=1; i <= this.numPages; i++) {
        divElem = document.getElementById(this.getPagenationId(this.divId,i));
        //remove this div (and regenerate it later)
        divElem.parentNode.removeChild(divElem);
    }
}

//add the divs for when we do paging
AvailableSection.prototype.addPagingDivs = function(pageNum) {

        var html = [];
        //page selector buttons
        if (this.numPages > 1) {
            html.push('<hr class=\"availHeadLine\">');
            html.push('<div>');
            //prev button
            if (pageNum > 1) {
                html.push('<span class="prevButton">');
                html.push('<a onclick="CrtLayoutElement.availableSections[\'' + this.sectionId + '\'].swapPages(' + pageNum +',' + (pageNum-1) + ');">');
                html.push(CrtLayoutElement.PAGE_PREV_IMG);
                html.push(CrtLayoutElement.PAGE_PREV);
                html.push('</a>');
                html.push('</span>');
            }
            //next button
            if (pageNum < this.numPages) {
                html.push('<span class="nextButton">');
                html.push('<a onclick="CrtLayoutElement.availableSections[\'' + this.sectionId + '\'].swapPages(' + pageNum + ',' + (pageNum+1) + ');">');
                html.push(CrtLayoutElement.PAGE_NEXT);
                html.push(CrtLayoutElement.PAGE_NEXT_IMG);
                html.push('</a>');
                html.push('</span>');
            }
            html.push('</div>');
        }
        return html.join('');
}
CrtLookupSection.prototype.getFieldFromMeta = function(primObjMData, fieldsMData, path,fieldName) {
    var iFieldSep = path.lastIndexOf('.');
    var iSep = path.indexOf('.');
    var table = primObjMData[path.substring(0,iSep)].table;
    var lookup;
    while (iSep != iFieldSep) {
        lookup = path.substring(iSep+1,path.indexOf('.',iSep+1));
        table = fieldsMData[table][lookup].lookup;
        iSep = path.indexOf('.',iSep+1);
    }
    lookup = path.substring(iSep+1);
    table = fieldsMData[table][lookup].lookup;
    return fieldsMData[table][fieldName];
}

CrtLookupSection.prototype.insertFieldCollection = function(fieldCollection,primObjMData,fieldsMData) {
    var allFieldKeys = fieldCollection.getAllFieldKeys();
    var newFields = [];
    for (var i=0; i<allFieldKeys.length; i++) {
        //make sure we are not trying to add an existing column
        var fieldKey;
        var crtFieldObj = fieldCollection.getField(allFieldKeys[i]);
        //find the existing fieldKey for this objectPath+field if available or else
        if (CrtLayoutElement.initialStateColIdMap[crtFieldObj.objectPath+CrtLayoutElement.FIELD_SEP+crtFieldObj.field]) {
            fieldKey = this.createFieldKey(crtFieldObj,CrtLayoutElement.initialStateColIdMap[crtFieldObj.objectPath+CrtLayoutElement.FIELD_SEP+crtFieldObj.field]);
        } else {
        //create a new lookupfield in the section and add it to fields collection
            fieldKey = this.createFieldKey(crtFieldObj,"");
        }

        //get metadata based on path
        var dataField = this.getFieldFromMeta(primObjMData,fieldsMData,crtFieldObj.objectPath,crtFieldObj.field);
        this.addField(new AvailableField(this.sectionId,fieldKey,dataField.label,true,true));
        newFields.push(this.fields[fieldKey]);
    }
    this.moveFields(newFields);
}


CrtLookupSection.prototype.createFieldKey = function(crtFieldObj, colId) {
    return crtFieldObj.objectPath+CrtLayoutElement.FIELD_SEP+crtFieldObj.field+CrtLayoutElement.COL_SEP+colId;
}

CrtLookupSection.prototype.getField = function(fieldId) {
    return this.fields[fieldId];
}

AvailableSection.prototype.swapToPage = function(pageNum){
    if (!pageNum) {
        pageNum = 1;
    }
    document.getElementById(this.getPagenationId(this.divId,pageNum)).style.display = 'block';
    this.currentPage = pageNum;
    CrtLayoutElement.currentDisplayedSec = this;
}

AvailableSection.prototype.swapPages = function(fromPageNum,toPageNum) {
    this.swapFromPage(fromPageNum);
    this.swapToPage(toPageNum);
}
AvailableSection.prototype.swapFromPage = function(pageNum) {
    if (!pageNum) {
        pageNum = this.currentPage;
    }
    document.getElementById(this.getPagenationId(this.divId,pageNum)).style.display = 'none';
    CrtLayoutElement.currentDisplayedSec = null;
}


/**
*     Manages the skiplinks and associated hovering lists
*     at the top of the detail page
*     see RelatedListPanelElement
* @author mpolcari
* @since 142.ml
*/
function RelatedListPanel(rlPanelId) {
  this.panelId = rlPanelId;
  this.currentListId = null;
  this.delayingHide = null;
  this.delayingShow = null;
  this.numLists = 0;
  this.linksHtml = [];
  this.isConsole = location.search.indexOf(Desktop['IS_DESKTOP']) > -1;
}

RelatedListPanel.prototype.getPanelNode = function() {
  return document.getElementById(this.panelId);
}

RelatedListPanel.prototype.getPanelShadowNode = function() {
  return (this.getPanelNode()) ? this.getPanelNode().parentNode : null;
}

RelatedListPanel.prototype.getIFrameNode = function() {
  return DomUtil.findDescendantWithTag(this.getPanelNode(), 'iframe');
}

RelatedListPanel.prototype.registerList = function(relatedList) {
  this.linksHtml.push(this.getHoverableLinkHTML(relatedList));
}

/**
* Adds the hoverLinks to the panel
*      must be run after onLoad()
*/
RelatedListPanel.prototype.addListsToPanel = function() {
  var linksNode = this.getHoverableLinksNode();
  if (linksNode.innerHTML.indexOf("linklet") < 0) {
    linksNode.innerHTML = this.linksHtml.join('<span class="pipe"> | </span>');
  }
  linksNode.style.visibility = 'visible';
}

RelatedListPanel.prototype.getHoverableLinkHTML = function (relatedList) {
  var buf = [];
  buf.push('<a class="linklet" href="#');
  buf.push(relatedList.getLinkTarget());
  buf.push('" id="');
  buf.push(this.getLinkId(relatedList.listId));
  buf.push('"');
  if(!relatedList.isOnlySkipLink){
	  buf.push(' onmouseover="sfdcPage.relatedListPanel.showRLDelayed(\'');
	  buf.push(relatedList.listId);
	  buf.push('\')" onmouseout="sfdcPage.relatedListPanel.hideRLDelayed(\'');
	  buf.push(relatedList.listId);
	  buf.push('\')" onclick="sfdcPage.relatedListPanel.hideRL(\'');
	  buf.push(relatedList.listId);
  }
  buf.push('\')"><span class="listTitle">');
  buf.push(relatedList.getTitle());
  buf.push(this.getCountIndicator(relatedList));
  buf.push('</span></a>');
  return  buf.join('');
}

RelatedListPanel.prototype.getCountIndicator = function (relatedList) {
  var html = [];
  html.push('<span class="count">[');
  html.push(relatedList.getNumberVisibleRows());
  if (relatedList.hasMore()) {
    html.push('<span class="plus">+</span>');
  }
  html.push(']</span>');
  return html.join('');
}

RelatedListPanel.prototype.getHoverableLinksNode = function() {
  return this.getPanelShadowNode().nextSibling;
}

RelatedListPanel.prototype.showRLDelayed = function(rlId) {
  this.clearhidemenu();
  if (this.currentListId && (this.currentListId != rlId)) {
    this.hideRL(this.currentListId);
    this.populateRL(rlId);
    this.showRL(rlId);
  } else {
    //clearshowmenu();
    var self = this;
    this.delayingShow = setTimeout(function() {self.showRL(rlId);}, 500);
    this.populateRL(rlId); // This way the time it takes to populate the list is not part of the timing delay
  }
}

RelatedListPanel.prototype.hideRLDelayed = function(rlId, delay) {
  this.clearshowmenu();
  if (!delay) delay = 50;
  if (!rlId) rlId = this.currentListId;
  var self = this;
  this.delayingHide = setTimeout(function() { self.hideRL(rlId); }, delay);
}

RelatedListPanel.prototype.getStyleSheetHtml = function() {
  var sheetHtml = []
  for (var i = 0; i< document.styleSheets.length; i++){
    if (document.styleSheets[i].owningElement && document.styleSheets[i].owningElement.outerHTML) {
      sheetHtml.push(document.styleSheets[i].owningElement.outerHTML);
    }
  }
  return sheetHtml.join('');
}

RelatedListPanel.prototype.populateRL = function(rlId) {
  if (!rlId) rlId = this.currentListId;

  if (this.currentListId != rlId) {
    var panelFrameNode = this.getIFrameNode();
    if (!panelFrameNode) return;
    var relatedListNode = getElementByIdCS(rlId);
    var iFrameDoc =  panelFrameNode.contentWindow.document;

    if (!(relatedListNode && iFrameDoc)) return;
    this.currentListId = rlId;
    if (iFrameDoc.importNode) { //ffox
      iFrameDoc.body.innerHTML = '';
      iFrameDoc.body.appendChild(iFrameDoc.importNode(relatedListNode, false));
      iFrameDoc.body.firstChild.innerHTML = relatedListNode.innerHTML;
    } else if (relatedListNode.outerHTML) {
      iFrameDoc.body.innerHTML = relatedListNode.outerHTML; // ie
    } else {
      return false;
    }
    var self = this;
    setTimeout(function() { self.fixContent(); }, 1);  //fire this asynchronously
    panelFrameNode.contentWindow.navigateToUrl = function(url) {
    	// window here actually refers to contentWindow.parent because of the context it's executed in, strange huh?
        window.navigateToUrl(url);
      };
  }
}

//forceResize: without forceResize, we will not resize the iframe
//             if the rl in question is already displayed
RelatedListPanel.prototype.showRL = function(rlId, forceResize) {
    this.clearhidemenu();

    if (rlId != this.currentListId) return;  //if the id's don't match, the panel has been cleared since the last hover.  It should not display
    var panelShadowNode = this.getPanelShadowNode();
    if (!panelShadowNode) return;
    var panelFrameNode = this.getIFrameNode();
    var linkletNode = getElementByIdCS(this.getLinkId(rlId));
    var relatedListNode = DomUtil.findDescendantWithClassName(getElementByIdCS(rlId), 'bPageBlock');
    if (!( panelFrameNode && linkletNode)) return;
    if (linkletNode.className.indexOf('linkletOn') > 0 && (!forceResize)) return;
    panelShadowNode.style.top = (linkletNode.offsetTop + linkletNode.offsetHeight) + "px";
    if (this.isConsole) {
    	//console has no margins, so this needs to be narrower
        panelShadowNode.style.left = (getObjX(this.getHoverableLinksNode()) - 4) + "px";
        panelShadowNode.style.width = (relatedListNode.offsetWidth - 3) + "px";
    } else {
        panelShadowNode.style.left = (getObjX(this.getHoverableLinksNode()) - 14) + "px";
        panelShadowNode.style.width = (relatedListNode.offsetWidth + 13) + "px"; //5 for each margin + 2 for shadow + 1 for border
    }
    panelFrameNode.style.height = (relatedListNode.offsetHeight + 5) + "px";
    panelShadowNode.style.display = 'block';
    linkletNode.className += ' linkletOn';
}


RelatedListPanel.prototype.hideRL = function(rlId) {
  if (!(Modal.isBlocked())) {
    this.clearshowmenu();
    if (!rlId) rlId = this.currentListId;
    this.currentListId = null;
    var panelShadowNode = this.getPanelShadowNode();
    var linklet = getElementByIdCS(this.getLinkId(rlId));
    if (linklet) linklet.className = 'linklet';
    if (panelShadowNode) panelShadowNode.style.display = 'none';
  }
}

RelatedListPanel.prototype.clearhidemenu = function(){
  if (this.delayingHide) {
    clearTimeout(this.delayingHide);
  }
}

RelatedListPanel.prototype.clearshowmenu = function(){
  if (this.delayingShow) {
    clearTimeout(this.delayingShow);
  }
}

RelatedListPanel.prototype.getLinkId = function (relatedListId) {
  return relatedListId + '_link';
}

RelatedListPanel.prototype.fixContent = function() {
  var targetableTags = ['a', 'form'];

    var iframeWin = this.getIFrameNode().contentWindow;

  for (var i = 0, tag; tag = targetableTags[i]; i++) {
    var tags = iframeWin.document.body.getElementsByTagName(tag);
    for (var k = 0, node; node = tags[k]; k++) {
      if (!node.target) { node.target = '_parent'; }
    }
  }
    var scripts = iframeWin.document.body.getElementsByTagName("script");
    for (var i = 0; i < scripts.length; i++) {
        iframeWin.eval(scripts[i].innerHTML);
    }
}


/**
 * Animation related functions and constants
 * @author mpaksoy
 * @since 150
 */
var Animation = {
    // This function is created under window when animations are in progress.
    ANIMATION_SLAVE : '_animationEventHandler',
    
    RESIZE_HEIGHT_STEPS : 8,
    RESIZE_HEIGHT_DELAY : 20, // milliseconds
    
    animations : {},
    
     /**
     * Animates the given element resizing it from from the starting height to final height.
     * @param elem DOMElement to manipulate
     * @param heightBefore height of the element at the beginning (the element is initialized according to this)
     * @param heightAfter height of the element at the end.
     *                    if set to -1, element's unmodified height as indicated by scrollHeight is used.
     * @param finalize function called once the resize animation is complete
     */
    animateResizeHeight : function(/*DOMElem*/ elem, /*number*/ heightBefore, /*number*/ heightAfter, /*function*/ finalize) {
        if (!elem) return;

        var savedState;
        var autoFinalHeight = false;
        if (Animation.animations[elem]) { // stop old animation
            savedState = Animation.animations[elem];
            savedState.clean();
        } else {
            savedState = {};
            savedState.height = XBrowser.getElementStyle(elem, 'height');
            savedState.overflow = elem.style.overflow;
        }

        Animation.animations[elem] = savedState;
        elem.style.overflow = 'hidden';

        if (heightAfter === -1) {
            elem.style.height = heightBefore + 'px';
            elem.style.display = 'block'
            heightAfter = XBrowser.getActualHeight(elem, true);
            autoFinalHeight = true;
        }

        var self = this;
        var series = Animation._getLinearSeries(heightBefore, heightAfter, Animation.RESIZE_HEIGHT_STEPS);
        if (autoFinalHeight && XBrowser.userAgent.isFirefox) {
            // Firefox does not like it when we end animation at the exact final height of the
            // element. So we skip the last step of the animation to force Firefox to redraw
            // correctly.
            series.pop();
        }
        var i = 0;

        savedState.clean = function() {
            elem.style.height = savedState.height;
            elem.style.overflow = savedState.overflow;
            clearInterval(savedState.intervalHandle);
            Animation.animations[elem] = null;
            if (finalize) finalize();
        };

        savedState.stepper = function() {
            if (i < Animation.RESIZE_HEIGHT_STEPS) {
                var curHeight = series[i];
                elem.style.height = curHeight + 'px';
                i++;
            } else {
                savedState.clean();
            }
        };
        savedState.intervalHandle = setInterval(savedState.stepper, Animation.RESIZE_HEIGHT_DELAY);
        savedState.stepper();
    },
    
    /** Animate element coming into view. Wrapper around animateResizeHeight. */
    rollIn : function(element, finalize) {
        Animation.animateResizeHeight(element, 1,-1, finalize);
    },
    
    /** Animate element going out of view. Wrapper around animateResizeHeight. */
    rollOut: function(element, finalize) {
        element.style.display = 'block';
        Animation.animateResizeHeight(element, XBrowser.getActualHeight(element), 1, function() {
                element.style.display = 'none';
                if (finalize) finalize();
            });
    },
    
    /**
     * Bring element into view, wait delay milliseconds, and bring element out of view.
     * Nice for notifications.
     */
    rollInRollOut : function(element, delay, finalize) {
        Animation.rollIn(element, function() {
                setTimeout(function() {Animation.rollOut(element, finalize)}, delay)
            });
    },
    
    /**
     * Fade in/out the element from the starting opacity to the final opacity.
     * @param elem DOMElement to manipulate
     * @param opacityBefore percent opacity at the beginning
     * @param opacityBefore percent opacity at the end
     * @param finalize function called once the resize animation is complete
     */
    animateOpacity : function(/*DOMElem*/ elem, /*number*/ opacityBefore, /*number*/ opacityAfter, /*function*/ finalize) {
        if (!elem) return;
        
        if (window[Animation.ANIMATION_SLAVE]) { // animation in progress, stop
            return;
        }
    
        // clean up parameters
        if (opacityBefore < 0) {
            opacityBefore = 0;
        } else if (opacityBefore > 100) {
            opacityBefore = 100;
        }
        if (opacityAfter < 0) {
            opacityAfter = 0;
        } else if (opacityAfter > 100) {
            opacityAfter = 100;
        }
    
        // TODO relative step sizes! (duration/smoothness based animation)
        var STEP = 5; // percent opacity
        var DELAY = 20; // milliseconds
        var self = this;

        var isIncreasing = (opacityBefore < opacityAfter);
        currentOpacity = Animation.setOpacity(elem, opacityBefore);
        if (opacityBefore == opacityAfter) {
            return
        }
        window[Animation.ANIMATION_SLAVE] = function() {
            if ((isIncreasing && (currentOpacity > opacityAfter)) ||
                ((!isIncreasing) && (currentOpacity < opacityAfter))) {
                window[Animation.ANIMATION_SLAVE] = false;
                Animation.setOpacity(elem, opacityAfter);
                if (finalize) finalize();
                return;
            }
    
            if (isIncreasing) {
                currentOpacity = Animation.setOpacity(elem, currentOpacity+STEP);
            } else {
                currentOpacity = Animation.setOpacity(elem, currentOpacity-STEP);
            }
            setTimeout('window.'+Animation.ANIMATION_SLAVE+'();', DELAY);
        }
    
        window[Animation.ANIMATION_SLAVE]();
    },
    
    // wrapper around animateOpacity
    fadeOut : function(/*DOMElem*/ elem, /*function*/ finalize) {
        Animation.animateOpacity(elem, 100, 0, finalize);
    },
    
    // wrapper around animateOpacity
    fadeIn : function(/*DOMElem*/ elem, /*function*/ finalize) {
        Animation.animateOpacity(elem, 0, 100, finalize);
    },
    
    // HELPER FUNCTIONS
    /**
     * Cross browser compatible opacity setter
     * @param element DOMElement to modify
     * @param opacity percent opacity to set (70 means 70%)
     * @return new opacity value
     */
    setOpacity : function(/*DOMElement*/ element, /*number*/ opacity) {
        if (XBrowser.userAgent.isIE) {
            element.style.filter = 'alpha(opacity='+opacity+')';
        } else {
            element.style.opacity = opacity/100;
        }
        return opacity;
    },
    
    /**
     * Crows browser compatible, opacity clear.
     * Makes element fully opaque/visible.
     */
    clearOpacity : function(/*DOMElement*/ element) {
        if (XBrowser.userAgent.isIE) {
            element.style.filter = 'alpha(opacity=100)';
        } else {
            element.style.opacity = 1;
        }
    },

    // PRIVATE HELPERS
    /**
     * Get an array of numbers that reprepsents a linear progression from the start point to end point.
     * The series always includes start and end points.
     * @param start starting point for series
     * @param end ending point for series
     * @param steps number of elements in the retured array
     * @return array of floating point numbers
     */
    _getLinearSeries : function(/* int */ start, /* int */ end, /* int */ steps) {
        ret = [];
        steps -= 1; // count the beginning point as a step
        ret.push(start)
        step = (end - start) / steps;
        var current = start;
        for (var i = 0; i < (steps - 1); i++) {
            current += step;
            ret.push(current);
        }
        ret.push(end);
        return ret;
    }
}

/**
 * Functions for handling the defaulting of Additional To, CC and BCC fields on the Email Author
 * page.  A lookup popup window is opened where additional values can be selected and populated
 * back on the Email Author page.
 * @author ccopek
 * @since 150
 */

function EmailCCBccLookup() {}

EmailCCBccLookup.prototype.storeAddrs = function(select, names, addrs, skipValue) {
	names.value = "";
  	addrs.value = "";
  	if (select != null) {
    	var isFirst = true;
    	for (var i=0; i<select.length; i++) {
      		if (select.options[i] != null && select.options[i].value != '' && select.options[i].value != skipValue) {
        		if (isFirst) {
	            	isFirst = false;
        		}
        		else {
          			names.value += EmailAuthorConstants.EMAIL_ADDR_DELIM;
          			addrs.value += EmailAuthorConstants.EMAIL_ADDR_DELIM;
        		}

        		names.value += select.options[i].text;
        		addrs.value += select.options[i].value;
      		}
    	}
	}
}

EmailCCBccLookup.prototype.storeAllAddresses = function(skipValue) {
    EmailCCBccLookup.prototype.storeAddrs(document.getElementById(EmailCCBccLookupConstants.ADDITIONAL_TO_ID),
    		   document.getElementById(EmailCCBccLookupConstants.ADDITIONAL_TO_NAME_ID),
    		   document.getElementById(EmailCCBccLookupConstants.ADDITIONAL_TO_ADDR_ID),
    		   skipValue);
	EmailCCBccLookup.prototype.storeAddrs(document.getElementById(EmailCCBccLookupConstants.CC_ID),
    		   document.getElementById(EmailCCBccLookupConstants.CC_NAME_ID),
    		   document.getElementById(EmailCCBccLookupConstants.CC_ADDR_ID),
    		   skipValue);
    EmailCCBccLookup.prototype.storeAddrs(document.getElementById(EmailCCBccLookupConstants.BCC_ID),
    		   document.getElementById(EmailCCBccLookupConstants.BCC_NAME_ID),
    		   document.getElementById(EmailCCBccLookupConstants.BCC_ADDR_ID),
    		   skipValue);
}

EmailCCBccLookup.prototype.changeContactType = function(skipValue) {
	EmailCCBccLookup.prototype.storeAllAddresses(skipValue);
	var form = document.forms[EditPageConstants.pEDIT_PAGE];
    form.submit();
    return true;
}

/**
 * A simple overlay screen for displaying a loading/saving method during ajax calls.
 * Currently used in check syntax links for S-Controls and Validation rules, as
 * well as for tag headers on detail pages during saving.
 *
 * @author agusev, emoses, jbergan
 */
function LoadingScreen(theDiv, waitingText, id){
    this.div = theDiv;
    this.text = waitingText;
    this.id = id;
}

LoadingScreen.prototype = {
    show : function() {
        if (!this.transparantElement){
            //Lazily create the div.
            this.createElements();
        }
        this.transparantElement.style.display = 'block';
        this.opaqueElement.style.display = 'block';
    },

    hide : function() {
        if (this.transparantElement) {
            this.transparantElement.style.display = 'none';
            this.opaqueElement.style.display = 'none';
        }
    },

    createElements : function() {
        // During construction in Safari, this is undefined, so it has
        // to be checked when show() is called.
        if (XBrowser.getCurrentStyle(this.div, "position") == "static"){
            this.div.style.position = 'relative';
        }

        // We have one overlay that is partially transparant, and one
        // that is not, so that the description will be opaque.
        this.transparantElement = this.createLoadingElement(this.div);
        this.transparantElement.className = 'waitingSearchDiv waitingSearchDivOpacity';
        this.opaqueElement = this.createLoadingElement(this.div);
        this.opaqueElement.className = 'waitingSearchDiv';
		if (this.id) {
	        this.opaqueElement.id = this.id;
		}

        // The loading description must be on a non-transparant div
        // because otherwise it will have the same opacity as the overlay,
        // and it doesn't look right to have semi-transparant text over text.
        this.addLoadingDescription(this.text, this.opaqueElement);
    },

    createLoadingElement : function(element) {
        var loading = document.createElement('div');

        // 100% is ideal, if it works, since it handles resizing correctly
        // and excludes the border of the element.
        loading.style.width = '100%';
        loading.style.height = '100%';
        if (XBrowser.userAgent.isIE) {
            // IE defaults to left being further left (-5 or so)
            loading.style.left = 0;
            // IE doesn't properly draw '100%' for height on the first try.
            loading.style.height = this.div.clientHeight + "px";
        }

        // Appending the overlay last helps work out the sizing done above
        element.appendChild(loading);
        return loading;
    },

    addLoadingDescription : function(description, element) {
        // On IE, a span ends up showing as two separate sections
        // (img and text) in some contexts.
        var newWaitingHolder = document.createElement('div');
        element.appendChild(newWaitingHolder);
        newWaitingHolder.className = 'waitingHolder';
        var limitedOffset = (element.offsetHeight)/5;
        if (limitedOffset > 100) {
            limitedOffset = 100;
        }
        newWaitingHolder.style.top =  limitedOffset + "px";

        var newWaitingImage = document.createElement('img');
        newWaitingHolder.appendChild(newWaitingImage);
        newWaitingImage.src = UserContext.getUrl('/img/loading.gif');
        newWaitingImage.className  = 'waitingImage';

        var newWaitingDescription = document.createElement('span');
        newWaitingHolder.appendChild(newWaitingDescription);
        newWaitingDescription.innerHTML =  description;
        newWaitingDescription.className  = 'waitingDescription';

		// for IE7, set the style to be position:absolute and width:auto, because the newWaitingImage.offsetWidth and newWaitingDescription.offsetWidth
		// might be 0
        if (XBrowser.userAgent.isIE7){
	        newWaitingHolder.style.position = 'absolute';
	        newWaitingHolder.style.width = 'auto';
		} else {
	        // This is a bit kludgy, but given the variety of widths this is used in,
	        // a straight percentage (as in the css) doesn't work.  Also, the extra 20
	        // is for safari, which otherwise ends up with too small a value for some reason.

	        newWaitingHolder.style.width = (newWaitingImage.offsetWidth + newWaitingDescription.offsetWidth + 20) + "px";
		}
        return newWaitingHolder;
    }
}
/*
 * Copyright, 1999-2006, SALESFORCE.com
 * All Rights Reserved
 * Company Confidential
 *
 * MobileConfig Object Javascript.
 * REQUIRES: DOJO-0.4.1.
 * @author dkothule
 * @since 148
 */

/*
    MobileConfig{
        id: null,
        querySets:[
            {	id: null,
                tableOrEnumId: null,
                parentId: null,
                recordLimit: 0,
                itemCount: 0,
				testResult: null,
				isTestResultCurrent: true,
				scope: null,
                items:[
                    {
                        id: null,
                        columnName: null,
                        operation: null,
                        value: null
                    }
                ],
                querySets:[
                ]
            }
        ]
    }

    ##ObjectDefinition is basic information about the object type that can be added in tree
    ObjectDefinition{
        "isTopLevel": true,
        "isCustom" : true,
        "type": "Product2",
        "label": "Product",
        "plural": "Products",
        "children": [
            "Task",
            "Event",
            "Activity"
        ]
    }
    ##MCXHRPost is information about xhr request - passed as a reference.
    MCXHRPost{
        isSync:false, //indicates request should be asynchronous or not
        isSuccess:true, //boolean flag indicating success or failure
        xhrInfo:[], //array of xhr params
        savingNode, //TreeNode object
        loadingNode, //TreeNode object
        callback //callback function that takes XHRPostRef object argument.
    }
*/

var MobileConfig = {
        baseObjectList: null, /*ObjectDefinition List*/
        id: null,

        dlgAdd: null,
        dlgWait: null,
        syncTree: null,
        syncTreeRoot: null,
        syncTreeController: null,
        syncTreeSelector: null,
        currentNode: null,
        formActionURL: null, /*original Form URL.*/
        filterPaneBody: null,
        lastFormAction: null, /*last action e.g. button click*/
        collisionParam: null,
        testResultsDisplayed: false,
        /**
         * Initializes MobileConfig object
         * @return void
         */
        init: function(){
            this.formActionURL = document.getElementById(EditPageConstants.pEDIT_PAGE).action;
            this.syncTree = dojo.widget.byId("syncTree");
            if(this.syncTree != null && this.syncTree.children != null && this.syncTree.children.length > 0){
                this.syncTreeRoot = this.syncTree.children[0];
                if(this.syncTreeRoot != null){
                    this.syncTreeRoot.object = {isRoot: true};
                    this.syncTreeRoot.isExpanded = true;
                }
                dojo.event.topic.subscribe("nodeSelected", MobileConfig.onSelectNode);
            }
            this.syncTreeController = dojo.widget.byId('syncTreeController');
            this.syncTreeSelector = dojo.widget.byId('syncTreeSelector');

            this.baseObjectList = MACInfo.BaseObjectList;
            
            this.collisionParam = MACInfo.CollisionParameter;

            this.filterPaneBody = dojo.widget.byId('filterPaneBody');

            this.onLoad();
            this.onSelectNode();

        }, /*::init::*/

        /**
         * Creates and initializes Add Dialog Box.
         * @return void
         */
        createAddDialog: function(){
            if(this.dlgAdd == null){
                this.dlgAdd = new AddSyncSetDialog()        
                sfdcPage.registerDialog(this.dlgAdd);        
            }
        },

		/**
		* Displays "Wait" dialog
		*/
		showWaitDialog: function(){
           if(this.dlgWait == null){
                this.dlgWait = new SimpleDialog("dlgWait", false);
                this.dlgWait.width = 200;                
                sfdcPage.registerDialog(this.dlgWait);
                this.dlgWait.setContentInnerHTML(LC.getLabel("MobileConfig_Section_SyncSet", "WaitDlg_Text"));
            }		
            if (this.dlgWait != null){
	            this.dlgWait.show();
            }            
		},
		
		hideWaitDialog: function(){
			if (this.dlgWait != null){
				this.dlgWait.hide();
			}
		},
		
		createTestErrorTooltip: function (id, msg){
			dojo.widget.createWidget( "tooltip", {connectId: id, caption: msg} );
		},
		
        /**
         * Returns the ObjectDefinition from base object list.
         * @return ObjectDefinition
         */
        getObjectDefinitionByType: function(/*string*/objType){
            if(this.baseObjectList && this.baseObjectList.length > 0){
                for(var i=0; i < this.baseObjectList.length; i++){
                    if(this.baseObjectList[i].type == objType){
                        return this.baseObjectList[i];
                    }
                }
            }
            return null;
        },

        /**
         * Returns the ObjectDefinition for Top-Level objects.
         * @param parent - by default it should be tree root.
         * @return ObjectDefinition[]
         */
        getTopLevelObjects: function(/*TreeNode*/ parent){
            var list = new Array();
            if(this.baseObjectList && this.baseObjectList.length > 0){
                var obj;
                for(var i=0; i < this.baseObjectList.length; i++){
                    obj = this.baseObjectList[i];
                    if(obj.isTopLevel == true){
                    	if(MACInfo.AllowMultipleEntities && (!MACInfo.MaxMultipleEntities || !this.findObjectInSiblings(parent, this.baseObjectList[i].type, MACInfo.MaxMultipleEntities))){
                    		list[list.length] = this.baseObjectList[i];
                    	}else if(parent && !this.findObjectInSiblings(parent, this.baseObjectList[i].type)){
                        	list[list.length] = this.baseObjectList[i];
                        }
                    }
                }
            }
            return list;
        },

        /**
         * OnLoad Hook. Initializes MobileConfig. Called upon body-onload.
         * @return void
         */
        onLoad: function(){
            var syncSet = JSUtils.getTextValue("SyncSet");
            if(syncSet != null){
                //dojo.debug("SyncSet:\n" + syncSet);
                syncSet = eval("("+syncSet+")");
                if(syncSet){
                    this.id = syncSet.id;
                    var qs = syncSet.querySets;
                    if(qs && qs.length > 0){
                        for(var i=0; i < qs.length; i++){
                            this.loadQuerySets(this.syncTreeRoot, qs[i]);
                        }
                    }
                    this.querySets = syncSet.querySets;
                }
            }
        },

        /**
         * Called before leaving the page.
         */
        onUnload: function(){
        	//disabled temporarily
            if(this.lastFormAction == "onSave"){
                //user already clicked on DONE, no need to save it.
                return true;
            }
            var result = this.onSave();
            if(!result){
                var msg = LC.getLabel("MobileConfig_Section_SyncSet", "AutoSave_PageUnloadError", MobileConfig.currentNode.title);
                return alert(msg);
            }
            
        },

        /**
         * OnSave Hook. Called upon when the form is submitted by clicking on done button.
         * @return returns true if save is successful; otherwise false.
         */
        onSave: function(){        	
            this.updateTreeData();
            var currentNode = MobileConfig.currentNode;
            if(currentNode && !MobileConfig.isRootNode(currentNode)){
                this.lastFormAction = "onSave";
                var xhrPost = {
                    "isSync" : true,
                    "savingNode": currentNode
                };
                MobileConfig.xhrPostSave(xhrPost);
                return (xhrPost.isSuccess == true);
            }
            return true;
        },

        /**
         * Updates the form element with tree data.
         * @return void
         */
        updateTreeData: function(){
            var result = {id: this.id, querySets: this.readQuerySets(this.syncTreeRoot)};
            JSUtils.setTextValue("SyncSet", dojo.json.serialize(result));
        },

        /**
         * Set the form action URL.
         * @param boolean xhrMode - if true, then sets to XHR otherwise; reset to default.
         * @return returns the form element.
         */
        setFormAction: function(/*boolean*/ xhrMode){
            //make sure that form action URL is pointing to right location;
            var form = document.getElementById(EditPageConstants.pEDIT_PAGE);
            form.action = (xhrMode == true? MACInfo.XHRHandlerURL : MobileConfig.formActionURL);
            return form;
        },

        /**
         * Loads the QuerySet in the tree recursively starting with given parent.
         * @return void
         */
        loadQuerySets: function(/*TreeNode*/parent, /*QuerySet*/qs){
        	qs.testResult = null;
        	qs.isTestResultCurrent = false;
            var node = this.addTreeNode(parent, qs.tableOrEnumId, qs);
            if(qs.querySets != null && qs.querySets.length > 0){
                for(var i=0; i < qs.querySets.length; i++){
                    this.loadQuerySets(node, qs.querySets[i]);
                }
            }
        },

        /**
         * Reads the QuerySet from the tree recursively.
         * @return QuerySet[]
         */
        readQuerySets: function(/*TreeNode*/parent){
            if(parent != null && parent.children != null && parent.children.length > 0){
                var child, qs, qsChildren;
                var qsArr = new Array();
                for(var i=0; i < parent.children.length; i++){
                    child = parent.children[i];
                    qs = child.object;
                    qsChildren = this.readQuerySets(child);
                    qs.querySets = qsChildren;
                    qsArr[qsArr.length] = qs;
                }
                return qsArr;
            }else{
                return null;
            }
        },

        /**
         * Adds the tree node
         * @return TreeNode - newly added node.
         */
        addTreeNode: function(/*TreeNode*/parent, /*string*/tableOrEnumId, /*QuerySet*/querySet){
            if(parent == null){
                dojo.debug("Can not add "+ tableOrEnumId + ". Parent is NULL");
                return;
            }
            var objDef = MobileConfig.getObjectDefinitionByType(tableOrEnumId);
            if(objDef == null){
                dojo.debug("Unable to find the object by type: " + tableOrEnumId);
                return;
            }
            querySet = querySet == null? {tableOrEnumId: tableOrEnumId} : querySet;
            var nodeId = querySet.id == null ? null : "Node_" + querySet.id;

            var filterImage = (querySet.itemCount != null && querySet.itemCount != 0) ? MACInfo.FilterIcon : "" ;
            var node = dojo.widget.createWidget("TreeNode", {title: objDef.label, object: querySet, afterLabel: filterImage});            
            
            //this is important for manual dojo parsing / performance improvement.
            djConfig.searchIds.push(node.widgetId);

            dojo.debug("Adding :" + objDef.label + "/" + tableOrEnumId + " WidgetId: " + node.widgetId + ", ID: " + node.id);
            node.isExpanded = true;
            parent.addChild(node);
            if (nodeId){
				node.titleNode.id = nodeId;
				var scopeTip = objDef.label;
				//the following comments ensure that the labels are loaded
				//LC.getLabel("FilterScope", "0");
				//LC.getLabel("FilterScope", "1");
				//LC.getLabel("FilterScope", "2");
				//LC.getLabel("FilterScope", "T");
				//LC.getLabel("FilterScope", "S");
				//LC.getLabel("FilterScope", "A");
				//LC.getLabel("FilterScope", "None");
				if (querySet.scope){
					scopeTip = scopeTip + ": " + LC.getLabel("FilterScope", querySet.scope);
				}else{
					scopeTip = scopeTip + ": " + LC.getLabel("FilterScope", "None");
				}
	            node.tooltip = dojo.widget.createWidget( "tooltip", {connectId: nodeId, caption: scopeTip} );	            
	        }
            return node;
        },

        /**
         * Gets the TreeNode starting from given node that has given object.
         * @param TreeNode parent - the node to start searching from (below)
         * @param string tableOrEnumId - the object type to look for
         * @return TreeNode - node with tableOrEnumId if found, otherwise null.
         */
        getTreeNode: function(/*TreeNode*/parent, /*string*/tableOrEnumId){
            if(parent != null && parent.children != null && parent.children.length > 0){
                var node, querySet;
                for(var i=0; i < parent.children.length; i++){
                    node = parent.children[i];
                    querySet = node.object;
                    if(querySet.tableOrEnumId == tableOrEnumId){
                        return node;
                    }
                }
            }
            return null;
        },

        /**
         * Removes the selected tree node. Updates the tree node icons and filter pane.
         * @return void
         */
        removeTreeNode: function(){
            var selectedNode = this.getSelectedNode();
            if(selectedNode != null && selectedNode.object != null && !selectedNode.object.isRoot){
                var next;
                var p = selectedNode.parent;
                this.syncTreeController.removeNode(selectedNode);
                if(!(p && p.children && p.children.length > 0)){
                    p.isFolder = false;
                }
                next = (p == null? this.syncTreeRoot : p);
                MobileConfig.selectNode(next);
                next.updateExpandIcon();
                this.syncTree.updateIconTree();
                MobileConfig.currentNode = null;
                //update selection
                MobileConfig.onSelectNode();
            }
        },

        /**
         * Checks whether given node is root node or not.
         * @return true, if the node is root, false otherwise.
         */
        isRootNode: function(/*TreeNode*/ node){
            return (node != null && node.object != null && node.object.isRoot == true);
        },

        /**
         * Updates the filter pane title.
         * @return void
         */
        updateFilterPaneTitle: function(title, filterPaneColor){
            if(title){
                JSUtils.setInnerHTML("filterPaneTitle", title);
                if(filterPaneColor){
                    dojo.html.setStyle("filterPaneBody", "background-color", filterPaneColor);
                }
            }
        },
        
        /**
         * Check for 302 condition.
         * @return string data.
         */
        checkFor302: function(data){
			//check for 302 error
	       	if(data && data.indexOf(MACInfo.XHRHandler302URL) != -1){
				if (window.location.replace){
					window.location.replace(MACInfo.MobileConfig302URL);
				}else{
					window.location.href = MACInfo.MobileConfig302URL;
				}
				return "";        		
	       	}
	       	MobileConfig.setFormAction(false);
	       	return data;
        },
        
        /**
         * Sends the XHR Post request to server
         * @param xhrPost is reference object containing post information.
         * @return void
         */
        xhrPostSave: function(/*MCXHRPost*/xhrPost){
            if(!(xhrPost && xhrPost.savingNode && xhrPost.savingNode.object && xhrPost.savingNode.object.id)){
                return;
            }
            var savingNode= xhrPost.savingNode; //short hand ref for better performance.
            if(MobileConfig.isRootNode(savingNode)){
                return;
            }
            var savingObj = savingNode.object;

            //change title to saving...
            MobileConfig.updateFilterPaneTitle(LC.getLabel("MobileConfig_Section_SyncSet", "FilterPane_Title_Saving", savingNode.title));

            this.updateTreeData();

            //prepare XHRInfo
            var xhrInfo = {};
            xhrInfo[MCXHRParams.pAction] = "SAVE";
            xhrInfo[MCXHRParams.pSaveObjType] = savingObj.tableOrEnumId;
            xhrInfo[MCXHRParams.pSaveObjId] = savingObj.id;
            xhrInfo[MCXHRParams.pCollisionParam] = MobileConfig.collisionParam;

            //save info post for later reference.
            xhrPost.xhrInfo = xhrInfo;

            var xhr = {
                xhrPost: xhrPost, /*reference for future use*/
                formNode: MobileConfig.setFormAction(true), /*use setFormAction(true) to change action to XHRHandler*/
                content: xhrInfo,
                sync: (xhrPost.isSync == true? true : false),
                load: function(type, data, event) {
                    //type parameter always have value "load"
                    data = MobileConfig.checkFor302(data);
		        			        	
                    //we got the html data, update the div.      
                    var result = eval("("+data+")");              
                    if (result && result[MCXHRParams.pIsSuccess]){
                    	xhrPost.isSuccess = true;
                    	xhrPost.savingNode.object.itemCount = result[MCXHRParams.pFilterItemCount];
                    	xhrPost.savingNode.object.scope = result[MCXHRParams.pScope];
                    	MobileConfig.collisionParam = result[MCXHRParams.pCollisionParam];                    	
                    }else{                    
                    	var content = (result && result[MCXHRParams.pData] ? result[MCXHRParams.pData] : "");
                    	xhrPost.isSuccess = false;
		                MobileConfig.filterPaneBody.setContent(content);
		            }                    
		            MobileConfig.onXHRPostSave(this.xhrPost, type);
                },
                error: function(type, errorObj){
                    //type parameter always have value "error"
                    MobileConfig.showFilterPaneError(errorObj.message);
                    xhrPost.isSuccess = false;
                    MobileConfig.onXHRPostSave(this.xhrPost, type);
                },
				encoding: "utf8"
            };
            dojo.io.bind(xhr);
        },

        /**
         * Generall callback for handling post-load request.
         * @param xhrPost - reference to xhrPost object
         * @param type - type of handler - either "load" or "error"
         */
        onXHRPostSave: function(/*MCXHRPost*/xhrPost, /*string*/type){
            //reset the form action to default one.
            MobileConfig.setFormAction(false);
            if(type=="load") {
				MobileConfig.onInitFilterPane();
			}
			if (!MobileConfig.isRootNode(xhrPost.savingNode)){
				MobileConfig.updateChangedNode(xhrPost.savingNode);
				MobileConfig.updateTestTotalsStyle(false);
			}

           //reset the loading title.
             MobileConfig.updateFilterPaneTitle(xhrPost.savingNode.title);
             //finally invoke the callback
             if(xhrPost && xhrPost.callback){
                 xhrPost.callback(xhrPost);
             }             
        },

        /**
         * Loads the filter pane for given node.
         * @param xhrPost is reference object containing post information.
         * @return void
         */
        xhrPostLoad: function(/*MCXHRPost*/xhrPost){
            if(!(xhrPost && xhrPost.loadingNode && xhrPost.loadingNode.object)){
            	MobileConfig.enableActionButtons(true);            
                return;
            }
            var loadingNode= xhrPost.loadingNode;
            var loadingObj = loadingNode.object;
            if(loadingObj.isRoot == true){
                MobileConfig.updateFilterPaneTitle(LC.getLabel("MobileConfig_Section_SyncSet", "FilterPane_DefaultTitle"), "#CCCCCC");
                MobileConfig.filterPaneBody.setContent("");    
                MobileConfig.enableActionButtons(true);            
                return;
            }
            //change title to loading and body color to white.
            MobileConfig.updateFilterPaneTitle(LC.getLabel("MobileConfig_Section_SyncSet", "FilterPane_Title_Loading", loadingNode.title), "#FFFFFF");

            //prepare XHRInfo
            var xhrInfo = {};
            xhrInfo[MCXHRParams.pAction] = "LOAD";
            xhrInfo[MCXHRParams.pLoadObjType] = loadingObj.tableOrEnumId;
            xhrInfo[MCXHRParams.pLoadObjId] =  loadingObj.id == null? "" : loadingObj.id;
            xhrInfo[MCXHRParams.pCollisionParam] = MobileConfig.collisionParam;

            //save info post for later reference.
            xhrPost.xhrInfo = xhrInfo;

            var xhr = {
                xhrPost: xhrPost, /*reference for future use*/
                formNode: MobileConfig.setFormAction(true), /*use setFormAction(true) to change action to XHRHandler*/
                content: xhrInfo,
                sync: (xhrPost.isAsync == true? true : false),
                load: function(type, data, event) {
                    //type parameter always have value "load"
                    data = MobileConfig.checkFor302(data);
                    
                    var result = eval("("+data+")");              
                    if (result && result[MCXHRParams.pIsSuccess] && result[MCXHRParams.pData]){
                    	xhrPost.isSuccess = true;
                    	MobileConfig.filterPaneBody.setContent(result[MCXHRParams.pData]);
                    	MobileConfig.onXHRPostLoad(this.xhrPost, type);
                    	MobileConfig.collisionParam = result[MCXHRParams.pCollisionParam];
                    }else{                    
                    	var content = (result && result[MCXHRParams.pData] ? result[MCXHRParams.pData] : "");
                    	xhrPost.isSuccess = false;
		                MobileConfig.filterPaneBody.setContent(content);
		            }		                                
                },/*load-handler*/

                error: function(type, errorObj){
                    //type parameter always have value "error"
                    MobileConfig.showFilterPaneError(errorObj.message);
                    xhrPost.isSuccess = false;
                    MobileConfig.onXHRPostLoad(this.xhrPost, type);
                }, /*error-handler*/
				encoding: "utf8"
            };
            dojo.io.bind(xhr);
        },

        /**
         * Generall callback for handling post-load request.
         * @param xhrPost - reference to xhrPost object
         * @param type - type of handler - either "load" or "error"
         */
        onXHRPostLoad: function(/*MCXHRPost*/xhrPost, /*string*/type){
            //reset the form action to default one.
            MobileConfig.setFormAction(false);
			
			if(type == "load") {
				MobileConfig.onInitFilterPane();
			}
            //reset the loading title.
            MobileConfig.updateFilterPaneTitle(xhrPost.loadingNode.title);
            //finally invoke the callback
            if(xhrPost && xhrPost.callback){
            	xhrPost.callback(xhrPost);
            }
        },
		
		/**
		 * This function is called to initialize the filter pane.
		 */
		onInitFilterPane: function(){
			try{
				//initialize filter criteria
				onLoadCriteria();
			}catch(e){
			}
			//Initialize scopes:
			MobileConfig.onChangeScope();
		},

        /**
         * Show filter pane error message - error from XHR.
         * @param string message - Error Message
         * @return void
         */
        showFilterPaneError: function(/*string*/ message){
            dojo.debug("XHR Error: " + message);
            MobileConfig.filterPaneBody.setContent("<strong>" + LC.getLabel("MobileConfig_Section_Filter", "ExceptionTitle") + "</strong>"
                + "<br><br><div class='errorMsg'>" + message + "</div>");
        },

        /**
         * Gets the selected TreeNode
         * @return TreeNode - selected node; null if not selected.
         */
        getSelectedNode: function(){
            if(this.syncTree != null && this.syncTree.selector != null){
                return this.syncTree.selector.selectedNode;
            }
            return null;
        },

        /**
         * Selects the given node in the tree.
         * To enforce single-item selection, this will un-select existing node.
         * @param TreeNode node - Node to be selected.
         * @return void
         */
        selectNode: function(/*TreeNode*/node){
            if(node){
                //enforce single node selection
                var sel = MobileConfig.getSelectedNode();
                if(sel){
                    this.syncTree.selector.deselect(node);
                }
                this.syncTree.selector.doSelect(node);
            }
        },
        
		/**
		 * Callback - called when radio button scope is changed (clicked).
		 */
		onChangeScope: function(/*radio*/ scope){
			//check if the none scope is initialized or not
			var showFC = true;
		
			//check if scope is passed, otherwise go thru all available scopes.
			if(scope == null){
				//for initialization:
				var scopes = document.getElementsByName(MCFilterPaneParams.pSCOPE);
				if(scopes && scopes.length > 0){
					for(var i=0; i < scopes.length; i++){
						if(scopes[i].value == MCFilterPaneParams.NONE_SCOPE_VALUE){
							showFC = !scopes[i].checked;
							break;
						}
					}
				}
			}else if(scope.value == MCFilterPaneParams.NONE_SCOPE_VALUE){
				showFC = false;
			}
			
			if(showFC){
				JSUtils.showEx("filterCriteriaBox", "maxRecordLimitNumRow");
			}else{
				JSUtils.hideEx("filterCriteriaBox", "maxRecordLimitNumRow");
				//select no limit checkbox for max records.
				JSUtils.setCheckbox(MCFilterPaneParams.pMAX_RECORD_RADIO + MCFilterPaneParams.pNO_LIMIT, true);
			}
			MobileConfig.maxRecordButtonHandler();
		},
		
        /**
         * Callback - called when node is selected.
         * Do not use "this" reference in this function.
         * @return void.
         */
        onSelectNode: function(){        	
            var /*TreeNode*/currentNode = MobileConfig.currentNode;
            var /*TreeNode*/selectedNode = MobileConfig.getSelectedNode();

            //Update the MobileConfig.currentNode only in this method.
            var loadCallback = function(xhrPost){
                if(xhrPost.isSuccess){
                    MobileConfig.currentNode = MobileConfig.isRootNode(xhrPost.loadingNode)? null : xhrPost.loadingNode;
                }else{
                    // rollback the selection. unselect loadingNode and select savingNode.
                    MobileConfig.selectNode(xhrPost.savingNode);
                }
                MobileConfig.enableActionButtons(true);
            };/*loadCallback*/

            var saveCallback =  function(xhrPost){
                if(xhrPost.isSuccess){
                    MobileConfig.currentNode = MobileConfig.isRootNode(xhrPost.loadingNode)? null : xhrPost.loadingNode;
                    //we need this to avoid posting the of the saved node data
                    MobileConfig.filterPaneBody.setContent("");                    
                    xhrPost.callback = loadCallback;
                    MobileConfig.xhrPostLoad(xhrPost);
                }else{
                    // rollback the selection. unselect loadingNode and select savingNode
                    MobileConfig.selectNode(xhrPost.savingNode);
                    MobileConfig.enableActionButtons(true);
                }                
            };/*saveCallback*/


            var xhrPost = {
                "savingNode" : currentNode,
                "loadingNode" : selectedNode
            };  
            MobileConfig.enableActionButtons(false);          
            if(currentNode != null){
            	
                //save currentNode first and then load selectedNode
                xhrPost.callback = saveCallback;
                return MobileConfig.xhrPostSave(xhrPost);
            }else{
                //load selectedNode
                xhrPost.callback = loadCallback;
                MobileConfig.xhrPostLoad(xhrPost);
            }
        },

        /**
         * Displays Add Dialog
         * @return void
         */
        showAddDialog: function(){
            if(MobileConfig.dlgAdd != null){            
            	this.dlgAdd.createContent();
                MobileConfig.dlgAdd.show();
            }else{
                dojo.debug("dialog is null");
            }
        },

        /**
         * Hides add dialog
         * @return void
         */
        hideAddDialog: function(){
            if(MobileConfig.dlgAdd != null){
                MobileConfig.dlgAdd.hide();
            }
        },

        /**
         * Callback - called when OK button on add dialog is clicked.
         */
        onOkAddDialog: function(){
            var sel = dojo.byId("dlgAdd_selectObj");
            if(sel != null){
                var selIndex = sel.selectedIndex;
                if(selIndex != -1){
                    var opt = sel.options[selIndex];
                    if(opt != null && opt.value != null && opt.value.length > 0){
                        var currentNode = this.getSelectedNode();
                        var parentNode = currentNode == null? this.syncTreeRoot : currentNode;
                        // create new queryset in the db
                        this.xhrCreateQuerySet(parentNode, opt.value);
                        this.hideAddDialog();
                    }
                }
            }
        },

        /**
         * Makes a call to MobileConfigXHRHandler to create a new query set in the database.
         * Used when adding a new node to the data set tree.
         */
        xhrCreateQuerySet: function(/*TreeNode*/ parent, optValue){
            var /*QuerySet*/ parentObject = parent == null? null : parent.object;
            var parentId = (parentObject && parentObject.id ? parentObject.id : "");
            
            // create new queryset in the database
            // prepare XHRInfo
            var xhrInfo = {};
            xhrInfo[MCXHRParams.pAction] = "CREATE";
            xhrInfo[MCXHRParams.pSaveObjType] = optValue;
            xhrInfo[MCXHRParams.pSaveObjParentId] = (parentObject && parentObject.id ? parentObject.id : "");
            xhrInfo[MCXHRParams.pCollisionParam] = MobileConfig.collisionParam;

            // XHR call to add the tree node in the database
            var xhr = {
                formNode: MobileConfig.setFormAction(true),
                content: xhrInfo,
                load: function(load, data, e) {
                    //check for 302 error
                    data = MobileConfig.checkFor302(data);
                    var result = eval("("+data+")");              
                    if (result && result[MCXHRParams.pIsSuccess] && result[MCXHRParams.pSaveObjId]){
                        var newQuerySetId = result[MCXHRParams.pSaveObjId];      
                        var scope = result[MCXHRParams.pScope];                   
                        var /*QuerySet*/ newObject = {tableOrEnumId: optValue, id: newQuerySetId, scope: scope};
                        if (parentId != ""){
             				newObject.parentId = parentId;
			            }
                        var /*TreeNode*/ newNode = MobileConfig.addTreeNode(parent, optValue, newObject);
                        MobileConfig.collisionParam = result[MCXHRParams.pCollisionParam];
                        MobileConfig.selectNode(newNode);
                        MobileConfig.onSelectNode();
                        MobileConfig.updateTestTotalsStyle(false);
                    }                    
                    else {
                        // server-side error occured
                        MobileConfig.filterPaneBody.setContent(result[MCXHRParams.pData]);
                    }
                },
                error: function(t, e) {
                    MobileConfig.setFormAction(false);
                    MobileConfig.showFilterPaneError(e.message);
                },
				encoding: "utf8"
            };
            dojo.io.bind(xhr);
        },

        /**
         * Makes a call to MobileConfigXHRHandler to delete a query set from the database.
         * Used when removing a node from the data set tree.
         */
        xhrDeleteQuerySet: function(/*TreeNode*/ delNode){
            var /*QuerySet*/ delObject = delNode == null? null : delNode.object;

            if (delObject == null || delObject.isRoot){
                return;
            }

            // delete the queryset
            // prepare XHRInfo
            var xhrInfo = {};
            xhrInfo[MCXHRParams.pAction] = "DELETE";
            xhrInfo[MCXHRParams.pSaveObjId] = (delObject && delObject.id ? delObject.id : "");
            xhrInfo[MCXHRParams.pCollisionParam] = MobileConfig.collisionParam;

            // XHR call to delete the query set from the database
            var xhr = {
                formNode: MobileConfig.setFormAction(true),
                content: xhrInfo,
                load: function(load, data, e) {
                	data = MobileConfig.checkFor302(data);
                    var result = eval("("+data+")");              
                    if (result && result[MCXHRParams.pIsSuccess]){
                        MobileConfig.filterPaneBody.setContent("");
                        MobileConfig.collisionParam = result[MCXHRParams.pCollisionParam];
                        MobileConfig.removeTreeNode();         
                        MobileConfig.updateTestTotalsStyle(false);               
                    }
                    else {
                        // server-side error occured
                        MobileConfig.filterPaneBody.setContent(result[MCXHRParams.pData]);    
                        MobileConfig.updateTestTotalsStyle(false);
                    }
                },
                error: function(t, e) {
                    MobileConfig.setFormAction(false);
                    MobileConfig.showFilterPaneError(e.message);
                },
				encoding: "utf8"
            };
            dojo.io.bind(xhr);
        },

		getQuerySetTestResult: function(results, querySetId){
			if (results == null || !(results instanceof Array) || results.length == 0){
				return null;
			}
			for (var i=0; i < results.length; i++){
				if( results[i].id == querySetId){
					return results[i];
				}
			}
			return null;
		},

		/**
		*  Display test data size result for the tree nodes (query sets)
		*/
        setQuerySetsTestResult: function(/*TreeNode*/parent, results){
        	if (parent != null){
        		if ( !MobileConfig.isRootNode(parent)){
        			var querySet = parent.object;
					var qsTestResult = results ? this.getQuerySetTestResult(results, querySet.id) : null;
					querySet.testResult = qsTestResult;
					querySet.isTestResultCurrent = true;
					MobileConfig.refreshAfterNodeHTML(parent);
        		}
	        	if (parent.children != null){
	        		for (var i=0; i<parent.children.length; i++){
	        			this.setQuerySetsTestResult(parent.children[i], results);
	        		}
	        	}
	        }        	
        },
        
        
        /**
        * Update filter icon and test data size results on UI
        */
       refreshAfterNodeHTML: function(/*TreeNode*/ node){
        	if ( node != null && !MobileConfig.isRootNode(node) ){
	       		var querySet = node.object;
	       		var qsTestResult = querySet.testResult;
				var filterImage = (querySet.itemCount != null && querySet.itemCount != 0) ? MACInfo.FilterIcon : "&nbsp;" ;	
				var testResult = qsTestResult ? " (" + qsTestResult.recordCount + ", " + qsTestResult.dataSize + ") " : "";				        	
	        	var testResultStyle = querySet.isTestResultCurrent ? "testResultsCurrent" : "testResultsModified";	
	        	var warningIconId = null;
	        	if (qsTestResult && qsTestResult.configError && qsTestResult.configError.length > 0){
	        		warningIconId = 'img_warning_' + querySet.id;
	        		testResult = testResult + MACInfo.WarningIcon.replace('%ID%', warningIconId);
	        	}
	        	node.afterLabelNode.innerHTML = filterImage + testResult;
	        	dojo.html.setClass(node.afterLabelNode, testResultStyle);
	        	if (warningIconId){
	        		MobileConfig.createTestErrorTooltip(warningIconId, qsTestResult.configError);
	        	}				
        	}
        },
        
        /**
        * Update saved node filter icon and test results. Update children nodes
        * is test results were current before 
        */        
        updateChangedNode: function(/*TreeNode*/ node){
        	if ( node != null && !MobileConfig.isRootNode(node) ){
        		var querySet = node.object;
        		var wasTestResultCurrent = querySet.isTestResultCurrent;
        		querySet.isTestResultCurrent = false;
        		MobileConfig.refreshAfterNodeHTML(node);
        		if (wasTestResultCurrent && node.children && node.children.length > 0){
        			for (var i=0; i<node.children.length; i++){
        				MobileConfig.updateChangedNode(node.children[i]);
        			}
        		}
        		//update the tooltip
        		var scopeTip = node.title;
				if (querySet.scope){
					scopeTip = scopeTip + ": " + LC.getLabel("FilterScope", querySet.scope);
				}else{
					scopeTip = scopeTip + ": " + LC.getLabel("FilterScope", "None");
				}
        		if (node.tooltip){
        			node.tooltip.uninitialize();
        		}
        		node.tooltip = dojo.widget.createWidget( "tooltip", {connectId: node.titleNode.id, caption: scopeTip} );
        	}
        },                
        
        /**
        * Update the style of test totals element based on whether the results are current (valid) or not
        */
        updateTestTotalsStyle: function(valid){
        	if (MobileConfig.testResultsDisplayed){        	
	        	var testResultsDiv = document.getElementById("testTotals");
	        	if (testResultsDiv){
		        	var className = valid ? "testResultsCurrent" : "testResultsModified";
		        	testResultsDiv.className = className;
		        	var estimateButton = document.getElementsByName("EstimateDataSize");
		        	if (estimateButton && estimateButton.length == 1){
		        		var buttonTextEstimate = LC.getLabel("MobileConfig_Section_SyncSet", "TestDataSize");
						var buttonTextRefresh = LC.getLabel("MobileConfig_Section_SyncSet", "RefreshDataSize");	        		
		        		estimateButton[0].value = valid ? buttonTextEstimate : buttonTextRefresh;
		        	}
	        	}
	        }
        },
        
        /**
        *	Display test data size results
        */
        displayTestDataResults: function(results) {
        	var qsTestResults = null;
        	var totals = "";
        	if (results){
 				var qsTestResults = results[MCXHRParams.pQSTestResults];
 				var totals = results[MCXHRParams.pTotalsElement];
        	}
	        this.setQuerySetsTestResult(this.syncTreeRoot, qsTestResults);
	        if (results){
	        	JSUtils.setInnerHTML("testDataSizeDiv", totals);	        	
	        }else{
	        	JSUtils.setInnerHTML("testTotals", "");	        	
	        }
	        MobileConfig.updateTestTotalsStyle(true);
	        MobileConfig.testResultsDisplayed = (results != null);       	
        },        
        
        /**
         * Makes a call to MobileConfigXHRHandler to test user data size
         */
        xhrPostTestDataSize: function(){
            // prepare XHRInfo
            var xhrInfo = {};
            xhrInfo[MCXHRParams.pAction] = "TESTDATASIZE";
            xhrInfo[MCXHRParams.pSaveObjId] = "";
			
            // XHR call to test datasize
            var xhr = {
                formNode: MobileConfig.setFormAction(true),
                content: xhrInfo,
                load: function(load, data, e) {
                	data = MobileConfig.checkFor302(data);                	
					var result = eval("("+data+")");
					if (result && result[MCXHRParams.pIsSuccess]){						
						MobileConfig.displayTestDataResults(result);
					}else
					{
						JSUtils.setInnerHTML("testTotals", result[MCXHRParams.pData]);
						MobileConfig.updateTestTotalsStyle(true);
					}					
	                MobileConfig.hideWaitDialog();
                },
                error: function(t, e) {
                    MobileConfig.setFormAction(false);
                    MobileConfig.showFilterPaneError(e.message);
                    MobileConfig.hideWaitDialog();
                },
				encoding: "utf8"
            };
            MobileConfig.showWaitDialog();
            dojo.io.bind(xhr);
        },        

        onCancelAddDialog: function(){
            this.hideAddDialog();
        },

        onTreeMenuAdd: function(){
            MobileConfig.onAddSyncObj();
        },

        onTreeMenuRemove: function(){
            MobileConfig.onRemoveSyncObj();
        },

        onAddSyncObj: function(){
            this.populateObjectList(this.getSelectedNode());            
            this.showAddDialog();
        },

        onRemoveSyncObj: function(){
            this.xhrDeleteQuerySet(this.getSelectedNode());
        },
		
		onTestDataSize: function(){		
			
            var currentNode = MobileConfig.currentNode;

            var loadCallback = function(xhrPost){
                if(xhrPost.isSuccess){
                	//load the currect node
                	MobileConfig.clearTestResults();
                    MobileConfig.xhrPostTestDataSize(xhrPost);
                }else{
					//error????
                }            
            };

            var saveCallback =  function(xhrPost){
                if(xhrPost.isSuccess){
					xhrPost.callback = loadCallback;                	
                	//load the currect node
                	MobileConfig.xhrPostLoad(xhrPost);
                }else{
					//error????
                }
            };            

            var xhrPost = {
                "savingNode" : currentNode,
                "loadingNode" : currentNode
            };
                        
            if(currentNode != null){
                //save currentNode first and then load selectedNode
                xhrPost.callback = saveCallback;
                MobileConfig.xhrPostSave(xhrPost);
            }else{
                //load selectedNode
                xhrPost.callback = null;
                MobileConfig.clearTestResults();
                MobileConfig.xhrPostTestDataSize(xhrPost);
            }
		},
		
		findObjectInSiblings: function(/*TreeNode*/ parent, /*string*/ objectType, /*int*/ maxMultipleObjects ){
            if(objectType && parent && parent.children && parent.children.length > 0){
            	var /*TreeNode*/ sibling;
            	var counter = 0;
            	var max = maxMultipleObjects ? maxMultipleObjects : 1;
            	for(var i=0; i < parent.children.length; i++){
            		sibling = parent.children[i];
            		if(sibling && sibling.object && sibling.object.tableOrEnumId && sibling.object.tableOrEnumId == objectType){
            			counter++;
            			if (max == counter){
	            			return true;
	            		}
            		}
            	}
            }
            return false;
		},
		
        findObjectInParent: function(/*TreeNode*/ parent, /*string*/objectType, /*boolean*/ searchSiblings, /*int*/ maxMultipleObjects){
            //lookup object type in parent hierarchy.
            var parentObj = parent? parent.object : null;
            if(parent != null && parentObj != null && objectType != null){
                if(parentObj){
                	//check optional searchSiblings
                	if(searchSiblings && this.findObjectInSiblings(parent, objectType, maxMultipleObjects)){
                		return true;
                	}
                    if(parentObj.isRoot){
                        return false;
                    }
                    if(parentObj.tableOrEnumId == objectType){
                        return true;
                    }
                    return this.findObjectInParent(parent.parent, objectType);
                }
            }
            return false;
        },

        populateObjectList: function(/*TreeNode*/parent){
            var /*Array*/ objDefList, /*string*/ parentObjType;

            parent = parent == null? this.syncTreeRoot : parent;
            parentObjType = parent.object.isRoot == true? null : parent.object.tableOrEnumId;
            parentObjLabel = null;

            if(parentObjType == null){
                objDefList = this.getTopLevelObjects(parent);
            }else{
                objDefList = new Array();
                var objDef = this.getObjectDefinitionByType(parentObjType);
                parentObjLabel = objDef? objDef.label : "";
                if(objDef){
                	var children, childDef;
                	var isTopLevelParent = MobileConfig.isRootNode(parent.parent);
                	children = objDef.children;
                	if(children && children.length > 0){
	                    for(var i=0; i < children.length; i++){
	                    	childDef = this.getObjectDefinitionByType(children[i].type);
	                    	if(!isTopLevelParent){
	                    		//exclude FKDomains (Child/Parent)
	                    		childDef = children[i].isFKDomain ? null : childDef;
	                    	}
	                    	var searchSiblings = !MACInfo.AllowMultipleEntities? true : children[i].isFKDomain || children[i].addOnlyOnce || MACInfo.MaxMultipleEntities;
	                    	var maxMultipleObjects = null;
	                    	if (searchSiblings){
		                    	if (!MACInfo.AllowMultipleEntities || children[i].isFKDomain || children[i].addOnlyOnce){
		                    		maxMultipleObjects = 1;
		                    	} else {
		                    		maxMultipleObjects = MACInfo.MaxMultipleEntities;
		                    	}
		                    }
	                        if(childDef && !this.findObjectInParent(parent, childDef.type, searchSiblings, maxMultipleObjects)){
	                        	objDefList[objDefList.length] = childDef;
	                        }
	                    }
                    }
                }
            }
            this.setObjectList(objDefList);
        },

        setObjectList: function(/*ObjectDefinition[]*/ objList){
            if(MobileConfig.dlgAdd == null){
                MobileConfig.createAddDialog();
            }
        	this.dlgAdd.setObjectList(objList);
        },

        /**
         * Event handler for the 'onClick' event of the set max record limit radio buttons
         */
        maxRecordButtonHandler: function(){
            var btnMaxRec = document.getElementsByName(MCFilterPaneParams.pMAX_RECORD_RADIO);
            var orderByDiv = document.getElementById(MCFilterPaneParams.pORDER_BY_DIV);
            if (orderByDiv != null && btnMaxRec != null){
                for(var i=0; i<btnMaxRec.length; i++){
                    if(btnMaxRec[i].checked){
                        if(btnMaxRec[i].value == MCFilterPaneParams.pNO_LIMIT){
                            orderByDiv.style.display = 'none';
                        }else{
                            orderByDiv.style.display = 'inline';
                        }
                        break;
                    }
                }
            }
        },

        /**
         * Event handler for the 'onFocus' event of the max record limit text input box
         */
        maxRecordTextBoxHandler: function(){
            var btnMaxRec = document.getElementsByName(MCFilterPaneParams.pMAX_RECORD_RADIO);
            var orderByDiv = document.getElementById(MCFilterPaneParams.pORDER_BY_DIV);
            if (orderByDiv != null && btnMaxRec != null){
                for(var i=0; i<btnMaxRec.length; i++){
                    if(btnMaxRec[i].value == MCFilterPaneParams.pSET_LIMIT){
                        btnMaxRec[i].checked = true;
                        orderByDiv.style.display = 'inline';
                    }else{
                        btnMaxRec[i].checked = false;
                    }
                }
            }
        },
        
        enableActionButtons: function(/*boolean*/ enable){         	
        	var buttonClass = enable ? "btn" : "btnDisabled";
        	var btns = new Array("add_button", "remove_button", "EstimateDataSize");
        	for (var i=0; i<btns.length; i++){
        		var btn = document.getElementById(btns[i]);        	
	        	if (btn){
    	    		btn.disabled = !enable;
    	    		btn.className = buttonClass;
        		}
        	}        	
        },
        
        clearTestResults: function(){
        	MobileConfig.displayTestDataResults(null);
        }
                                
};/*class: MobileConfig */


   function AdvCurrencyEnable() {}

   AdvCurrencyEnable.checkSaveButton = function(checkCheckBox) {
		var checked;
		if (checkCheckBox) {
			checked = document.getElementById(AdvancedCurrencyEnable.pENABLE).checked;
		} else {
			checked = ! document.getElementById(AdvancedCurrencyEnable.pENABLE).checked;
		}
 		//check if any of the input values are checked so that we allow the user to save by enabling the save button
   		if (checked) {
   			document.getElementsByName(AdvancedCurrencyEnable.enableButton)[0].className = 'btn';
            document.getElementsByName(AdvancedCurrencyEnable.enableButton)[0].disabled = false;
   		} else {
        	document.getElementsByName(AdvancedCurrencyEnable.enableButton)[0].className = 'btnDisabled';
            document.getElementsByName(AdvancedCurrencyEnable.enableButton)[0].disabled = true;
   		}
   }

var MultiSelectPicklist = {};

MultiSelectPicklist.loadMSP = function(id) {
    var sElem = getElementByIdCS(id + '_selected');
    var uElem = getElementByIdCS(id + '_unselected');
    
    //this is a stupid hack to keep the optgroup labels from disappearing
    if (isSafari) {
	    for(i=0; i < sElem.childNodes.length; i++) {
        	var ch = sElem.childNodes[i]
	        if (ch.nodeName == "OPTGROUP") {
	        	ch.appendChild(document.createElement("p"));
	        }
	    }
	    
   	    for(i=0; i < uElem.childNodes.length; i++) {
        	var ch = uElem.childNodes[i]
	        if (ch.nodeName == "OPTGROUP") {
	        	ch.appendChild(document.createElement("p"));
	        }
	    }
    }
    
    MultiSelectPicklist.resizeMSP(sElem, uElem);
}

MultiSelectPicklist.resizeMSP = function(sElem, uElem) {
    if (!sElem || !uElem) return;
    if (!sElem.style.width) {
        var selW = (sElem.scrollWidth > uElem.scrollWidth) ? sElem.scrollWidth : uElem.scrollWidth;
        selW = selW + 35;
        sElem.style.width = selW + "px";
        uElem.style.width = selW + "px";

    }
}

MultiSelectPicklist.handleMSPChange = function(sel) {
    var sElem = getElementByIdCS(sel.id + '_selected');
    var uElem = getElementByIdCS(sel.id + '_unselected');

    //Safari handles optgroups differently and requires explicit DOM manipulation
    if (isSafari) {
    	var sDepth;
    	var uDepth;
    	
	    for(i=0; i < sElem.childNodes.length; i++) {
        	var ch = sElem.childNodes[i]
	        if (ch.nodeName == "OPTGROUP") {
	        	sDepth = i;
				var chlen = ch.childNodes.length
        	    for(j=0; j<chlen; j++) {
            	    ch.removeChild(ch.childNodes[0]);
            	}
            	ch.appendChild(document.createElement("p"));
        	}
    	}
    	
    	for(i=0; i < uElem.childNodes.length; i++) {
        	var ch = uElem.childNodes[i]
	        if (ch.nodeName == "OPTGROUP") {
				uDepth = i;
				var chlen = ch.childNodes.length
        	    for(j=0; j<chlen; j++) {
            	    ch.removeChild(ch.childNodes[0]);
            	}
            	ch.appendChild(document.createElement("p"));
        	}
    	}
    	
    	for (i=0; i < sel.options.length; i++) {
    		if (sel.options[i].value != picklistNAMarker) {
			    var o = document.createElement("option");
			    o.text = sel.options[i].text;
			    o.value = i;
    			
    			if (sel.options[i].selected) {
    				sElem.childNodes[sDepth].appendChild(o);
    			} else {
    				uElem.childNodes[uDepth].appendChild(o);
    			}
    		}
    	}
    } else {
	    var sI = 0;
	    var uI = 0;

    	sElem.length = 0;
	    uElem.length = 0;
	    
	    for (var i = 0; i < sel.options.length; i++) {
	        if (sel.options[i].value != picklistNAMarker) {
	           if (sel.options[i].selected) {
	                sElem.options[sI] = new Option(sel.options[i].text, i);
	                sI++;
	            } else {
	                uElem.options[uI] = new Option(sel.options[i].text, i);
	                uI++;
	            }
	        }
	    }
    }

    MultiSelectPicklist.resizeMSP(sElem, uElem);
}

MultiSelectPicklist.handleMSPSelect = function(selId) {
    var mainElem = getElementByIdCS(selId);
    var uElem = getElementByIdCS(selId + '_unselected');
    for (var i = 0; i < uElem.options.length; i++) {
        if (uElem.options[i].selected) {
            mainElem.options[parseInt(uElem.options[i].value)].selected = true;
        }
    }
    MultiSelectPicklist.handleMSPChange(mainElem);
}

MultiSelectPicklist.handleMSPUnSelect = function(selId) {
    var mainElem = getElementByIdCS(selId);
    var sElem = getElementByIdCS(selId + '_selected');
    for (var i = 0; i < sElem.options.length; i++) {
        if (sElem.options[i].selected) {
            mainElem.options[parseInt(sElem.options[i].value)].selected = false;
        }
    }
    MultiSelectPicklist.handleMSPChange(mainElem);
}
function CalendarTaskList() {}

CalendarTaskList.verifySelected = function(form, element_name, errorMessage) {
	var initialCheck = verifyChecked(form, element_name, errorMessage);
	if (initialCheck) {
		var selected = 0;
		for (i = 0; i < form.elements.length; i++) {
	        if ((form.elements[i].name == element_name) && form.elements[i].checked) {
	            selected++;
	        }
		}
		if (selected > TaskMassAction.ROW_LIMIT) {
			alert(LC.getLabel('List', 'checkboxLimit', TaskMassAction.ROW_LIMIT));
			return false;
		}
		return true;
	}
	return initialCheck;
}

/**
 * Utility to save open/closed state of setup in browser cookies. 
 * The starting state of the setup tree is initialized in 
 * SetupPageHeader.java, which generates the value for openListSetup below.
 */

var SetupTreeNode = function(){}

// this variable is also referenced in SetupPageHeader.java
SetupTreeNode.prototype.openListSetup = new Array();

SetupTreeNode.prototype.addToOpenSetup = function(item) {
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] == null) {
            SetupTreeNode.prototype.openListSetup[i] = item;    
            SetupTreeNode.prototype.updateCookiesSetup();
            return;     
        }
    }
    SetupTreeNode.prototype.openListSetup[SetupTreeNode.prototype.openListSetup.length] = item;
    SetupTreeNode.prototype.updateCookiesSetup();
}

SetupTreeNode.prototype.removeFromOpenSetup = function(item) {   
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] == item) {
            SetupTreeNode.prototype.openListSetup[i] = null;            
        }
    }
    SetupTreeNode.prototype.updateCookiesSetup();
}

// class structure: parent->setupFolder->setupLeaf
SetupTreeNode.prototype.getNodes = function(){
	var allNodes = new Array();
	
	var parents = getElementsByClassName('parent');
	allNodes = allNodes.concat(parents);

	var leaves = getElementsByClassName('setupLeaf');
	allNodes = allNodes.concat(leaves);
	
	return allNodes;
	
}

SetupTreeNode.prototype.search = function(){
	if (SetupTreeNode.prototype.isTypingFast()){
		return;
	}
	var val = SetupTreeNode.prototype.getSearchTerm();
	if (!val) {
		SetupTreeNode.prototype.reset();
		return;
	}
	var vals = val.split(' ');
	if (!vals || vals.length == 0){
		return;
	}
	var elements = SetupTreeNode.prototype.getNodes();
	for (var i = 0; elements && i < elements.length; i++){
		var obj = elements[i];
		var topic = obj.id;
	    SetupTreeNode.prototype.searchNode(obj, topic, vals);
	}
}


SetupTreeNode.prototype.searchNode = function(obj, topic, vals){
    if (obj != null) {
    	var containsText = true;
    	var txt = obj.getAttribute(SetupSearchElement.ATT_SEARCH_TEXT);
    	if (!txt){
    		containsText = false;
    	} else {
	    	for (var j = 0; j < vals.length; j++){
	    		if (txt.indexOf(vals[j]) == -1){
	    			containsText = false;
	    			break;
	    		}
	    	}
    	}
        if (containsText) {
        	HTMLTreeNode.prototype.setVisible(obj, true);
        	if (obj.className == 'parent'){
        		obj = HTMLTreeNode.prototype.getNodeChild(topic);
        		HTMLTreeNode.prototype.open(obj, topic);
        	}
        } else {
        	HTMLTreeNode.prototype.setVisible(obj, false);
        	if (obj.className == 'parent'){
        		obj = HTMLTreeNode.prototype.getNodeChild(topic);
        		HTMLTreeNode.prototype.close(obj, topic);
        	}
        }
    }
}

SetupTreeNode.prototype.reset = function(){
	document.getElementById(SetupSearchElement.SETUP_SEARCH_PARAM).value = '';
	var elements = SetupTreeNode.prototype.getNodes();
	for (var i = 0; elements && i < elements.length; i++){
		var obj = elements[i];
	    HTMLTreeNode.prototype.setVisible(obj, true);
	}
}

SetupTreeNode.prototype.getSearchTerm = function(){
	var term = document.getElementById(SetupSearchElement.SETUP_SEARCH_PARAM).value;
	if (term){
		term = term.toLowerCase();
	}
	return term;
}

SetupTreeNode.prototype.updateCookiesSetup = function() {
    var stringlist = "";
    for (var i = 0; i < SetupTreeNode.prototype.openListSetup.length; i++) {
        if (SetupTreeNode.prototype.openListSetup[i] != null) {
            stringlist = stringlist + SetupTreeNode.prototype.openListSetup[i] + ":";
        }
    }
            
    Cookies.prototype.SetCookie(SetupTreeNodeConstants.COOKIE_KEY, stringlist, null, "/");     
}

SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS = 250;
SetupTreeNode.prototype.LAST_DATE = null;
SetupTreeNode.prototype.TIMEOUT_ID = null;

// if typing fast, will delay search() until after typing is slowed
SetupTreeNode.prototype.isTypingFast = function(){
    
    // clear existing timeout to avoid flood of delayed search calls
    if (SetupTreeNode.prototype.TIMEOUT_ID){    
        clearTimeout(SetupTreeNode.prototype.TIMEOUT_ID);
    }
    
	var d = new Date();
	if (SetupTreeNode.prototype.LAST_DATE == null){
	    SetupTreeNode.prototype.LAST_DATE = d;
	    return true;
	} else {
	    var diff = d.getTime() - SetupTreeNode.prototype.LAST_DATE.getTime();
	    SetupTreeNode.prototype.LAST_DATE = d;
	    if (diff < SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS){
	        var delayedExec = "SetupTreeNode.prototype.search();";
	        SetupTreeNode.prototype.TIMEOUT_ID = setTimeout(delayedExec, SetupTreeNode.prototype.TYPING_THRESHOLD_MILLIS);
	        return true;
	    } else {
	        return false;
	    }
	}
	
}


var CampaignInfluenceSetupUi = {};

CampaignInfluenceSetupUi.setAutomaticAssociation = function(enabled) {
    var i = 1;
    var nextField = document.getElementById('fcol'+i);
    var nextOp = document.getElementById('fop'+i);
    var nextVal = document.getElementById('fval'+i);

    while (nextField) {
        nextField.disabled = !enabled;
        nextOp.disabled = !enabled;
        nextVal.disabled = !enabled;
        i++;
        nextField = document.getElementById('fcol'+i);
        nextOp = document.getElementById('fop'+i);
        nextVal = document.getElementById('fval'+i);
    }

    var bool = document.getElementById('bool_filter');
    if (bool) bool.disabled = !enabled;

    var timeframe = document.getElementById('citf');
    if (timeframe) timeframe.disabled = !enabled;
}
var SIDEBAR_DIV_WIDTH = 216;
var SIDEBAR_DIV_EDGE = 19; //width of handle (b/w right edge and window edge when collapsed)
var SIDEBAR_DIV_SPACE = 0; //Between left edge and content when pinned
var SIDEBAR_RIGHT_INC = 20;
var SIDEBAR_TIMESTEP = 8;
var SIDEBAR_OUT_DELAY = 500;
var SIDEBAR_IN_DELAY = 100;
var SIDEBAR_BORDER_WIDTH = 1;	// used to align the handle with the sidebarDiv


/**
 *  Sidebar.  This is the controller object for the collapsible sidebar.
 *
 *  @author emoses
 *  @since 144
 *
 *  @param sidebarDiv      object. A reference to the sidebar div DOM object.
 *  @param enableCollapse  boolean.  True to enable the collapsible sidebar
 *  @param isPinnned	   boolean.  Whether the sidebar is initialized pinned
 *
 *  Note that isPinned is not required if enabledCollapse is false.
 */
function Sidebar(sidebarDiv, enableCollapse, isPinned) {
  this.div = sidebarDiv;
  this.inOutBox = document.getElementById(SidebarConstants.HANDLE_ID);
  // there are 2 handles, one at the bottom, one at the top
  this.handle = document.getElementById(SidebarConstants.PIN_INDICATOR_ID);
  this.handle2 = document.getElementById(SidebarConstants.PIN2_INDICATOR_ID);
  this.pinned = isPinned;

  this.openHandleRE = /\bopen\b/;

  if (!enableCollapse){
    /* Sidebar not enabled.  Kill the cookie if it exists, resize the sidebar to the
     * size of the body, and exit without instanciating this object
     */
    deleteCookie(SidebarConstants.SIDEBAR_PINNED_COOKIE);
  }

  //this is the reportOverview page and has no sidebar
  if ((enableCollapse) && (!this.pinned) && (!document.getElementById(BodyLayout.BODY_TABLE_ID)) && (document.body)) {
    document.body.className = document.body.className + ' hiddenSidebar';
  }

  if ((!enableCollapse) || (!document.getElementById(BodyLayout.BODY_TABLE_ID))) {
    this.handle.style.display = "none";
    this.handle2.style.display = "none";
    this.sizeBodyToSidebar();
    this.sizeToBody();

    return null;
  }


  //Some styles are specific to the collapsible sidebar
  this.div.className = "collapsible";

  /*private members*/
  var self = this;
  var outDelay = -1;
  var locked = false;

  /* instantiate the controller object for the moveIn/moveOut behavior.  This is all callbacks */
  this.mover = new Fader(
    this.div, //object
    function(object, currVal) { return currVal <= -1* (SIDEBAR_DIV_WIDTH-SIDEBAR_DIV_EDGE); },  //textMin
    function(object, currVal) { return currVal >= 0; }, //testMax
    SIDEBAR_TIMESTEP, //timestep
    function(currVal, sign){ return currVal += sign*SIDEBAR_RIGHT_INC; }, // nextStep
    function(object, nextVal){ object.setStyle('left', nextVal + "px"); }, //increment
    0, //startVal
    function(object) { object.style.left = (-1*(SIDEBAR_DIV_WIDTH-SIDEBAR_DIV_EDGE))+ "px"; return -1*(SIDEBAR_DIV_WIDTH-SIDEBAR_DIV_EDGE) }, //finalMin
    function(object) { object.style.left = "0px"; return 0; } //finalMax
  );

  this.handleInOutClick = function(e) {
    if (!locked){
      self.pin();
    }
  };

  this.handleDocumentKeyDown = function(e){
    var evt = getEvent(e);
    var pos = self.mover.getPosition();
    if (evt.altKey && String.fromCharCode(evt.keyCode) === "S"){
      //ALT-s
      //Highlight the text in the sidebar search area
      var searchBox = document.getElementById(SidebarConstants.pSEARCH_SIDEBAR_STR);
      if (searchBox){
        searchBox.focus();
        searchBox.select();
      }
      //reverse
      if (!locked){
        self.pin();
      }
    }
  };

  this.lock = function() {
    locked = true;
  };

  this.unlock = function() {
    locked = false;
  };

  this.init();
}

Sidebar.prototype.sizeToBody = function(){
  var content = document.getElementById(BodyLayout.BODY_TABLE_ID);
  if (content) {
    this.div.style.height = content.offsetHeight + "px";
    var newHeight = content.offsetHeight - SIDEBAR_BORDER_WIDTH;
    if(newHeight >= 0){
    	this.inOutBox.style.height = newHeight + "px";
    }
  }
};

Sidebar.prototype.sizeBodyToSidebar = function(){
  var content = document.getElementById(BodyLayout.BODY_TABLE_ID);
  if ((content) && (this.div.offsetHeight > content.offsetHeight)) {
    content.style.height = (this.div.offsetHeight - SIDEBAR_BORDER_WIDTH) + "px";
  }
};

Sidebar.prototype.sizeBodyToSidebarNoCheck = function(){
  var content = document.getElementById(BodyLayout.BODY_TABLE_ID);
  var inner = this.div.lastChild
  content.style.height = (inner.offsetHeight - SIDEBAR_BORDER_WIDTH) + "px";
};

/* public functions */
Sidebar.prototype.setSidebarCookie = function(val){
  var expires = new Date();
  expires.setTime(expires.getTime() + (3650*24*60*60*1000));
  setCookie(SidebarConstants.SIDEBAR_PINNED_COOKIE, val, expires);
};

Sidebar.prototype.getSidebarCookie = function(){
  return getCookie(SidebarConstants.SIDEBAR_PINNED_COOKIE);
};

Sidebar.prototype.init = function() {
  addEvent(document, 'keydown', this.handleDocumentKeyDown, false);
  addEvent(this.inOutBox, 'click', this.handleInOutClick, true);
  addEvent(this.handle, 'click', this.handleInOutClick, true);
  addEvent(this.handle2, 'click', this.handleInOutClick, true);

  this.sizeBodyToSidebar();
  this.div.display = "none";
  if (!this.pinned){
    this.pinned = true //Reverse it for the benefit of this.pin()
    this.pin(true);
  } else {
    document.getElementById(BodyLayout.BODY_CELL_ID).style.paddingLeft = SIDEBAR_DIV_WIDTH + "px";
  }
  this.setTitleAndClass();

  //Check for errors in the sidebar, and jump it out if need be

  if (getElementsByClassName(EditElement.ERROR_CLASS, this.div).length > 0){
    this.mover.jumpIn();
  }
};

Sidebar.prototype.pin = function(noCookie) {
  var content = document.getElementById(BodyLayout.BODY_CELL_ID);
  if (this.pinned){
    this.pinned = false;
    content.style.paddingLeft = (SIDEBAR_DIV_EDGE + SIDEBAR_DIV_SPACE) + "px";
    this.sizeToBody();
    this.mover.jumpOut();
    if (!noCookie) { this.setSidebarCookie("0"); }
  } else {
    this.pinned = true;
    content.style.paddingLeft = (SIDEBAR_DIV_WIDTH + SIDEBAR_DIV_SPACE) + "px";
    this.sizeToBody();
    this.mover.jumpIn();
    if (!noCookie) { this.setSidebarCookie("1"); }
  }
  this.setTitleAndClass();
};

Sidebar.prototype.setTitleAndClass = function() {
  if (this.pinned) {
    this.handle.title = LC.getLabel("Sidebar", "collapse");
    this.handle2.title = LC.getLabel("Sidebar", "collapse");
    this.inOutBox.title = LC.getLabel("Sidebar", "collapse");
    if (!this.handle.className.match(this.openHandleRE)) {
      this.handle.className += " open";
      this.handle2.className += " open";
    }
    if (!this.inOutBox.className.match(this.openHandleRE)) {
      this.inOutBox.className += " open";
    }
  } else {
    this.handle.title = LC.getLabel("Sidebar", "expand");
    this.handle2.title = LC.getLabel("Sidebar", "expand");
    this.inOutBox.title = LC.getLabel("Sidebar", "expand");
    this.handle.className = this.handle.className.replace(this.openHandleRE, "");
    this.handle2.className = this.handle.className.replace(this.openHandleRE, "");
    this.inOutBox.className = this.inOutBox.className.replace(this.openHandleRE, "");
  }
};

/**
 * JS code to handle filtering/querying in a SelectFilterElement.
 */
var SelectFilterElement = function(ctlName, ctlOption, target, targetOption, existing, max, useJs){

    this.controllerName = ctlName;
    this.controllerOption = ctlOption;
    this.targetName = target;
    this.targetOption = targetOption;
    this.existingName = existing;

    // array of selected Option objects
    this.selectedOptions = new Array();

    // array of array of all Option objects
    this.allOptions = new Array();
    this.maxValues = max;
    this.searchQueueCount = 0;
    this.useJsSearch = useJs;
    this.searchStringChanged = false;
    this.itemAdded = false;
}

SelectFilterElement.prototype.getSearchElementId = function(){
    return 'searchValue_' + this.controllerName;
}

SelectFilterElement.prototype.addOptions = function(array){
	for (var i = 0; i < array.length; i++){
		this.addOption.apply(this, array[i]);
	}
}

SelectFilterElement.prototype.addOption = function(type, label, key, searchValue, existingValues) {

    var opt = new Option(label, key);
    opt.searchValue = searchValue;
    var optionsArray = this.allOptions[type];
    if (!optionsArray){
        optionsArray = new Array();
        this.allOptions[type] = optionsArray;
    }
    optionsArray[optionsArray.length] = opt;

    if (existingValues && this.selectedOptions != null && this.selectedOptions[key]) {
        existingValues.options[existingValues.options.length] = new Option(label, key);
    }

}

// doing queueSearch only applies to js searching. otherwise,
// sever-side search results in LOTS of posts to server.
SelectFilterElement.prototype.queueSearch = function() {
    this.searchQueueCount++;
    var callback = this.getJavascriptVarName() + '.doSearch()';
    setTimeout(callback, 300);
}

SelectFilterElement.prototype.doSearch = function() {

    this.searchQueueCount--;
    if (this.searchQueueCount > 0) return;
    // Reset the queue when we do a search
    this.searchQueueCount = 0;

    if (this.useJsSearch){
        this.doSearchJS();
    } else {
        this.doSearchServer();
    }
}

// does a "search" by filtering the values in the select element
SelectFilterElement.prototype.doSearchJS = function() {

    var controller = document.getElementById(this.controllerName);
    var targetField = document.getElementById(this.targetName);
    var existing = document.getElementById(this.existingName);

    var searchEl = document.getElementById(this.getSearchElementId());
    var searchValue = searchEl.value ? searchEl.value.toLowerCase() : "";
    if (searchValue.length == 0) {
        // Just run the whole filter if the input length is 0
        this.filter();
        return;
    }

    targetField.options.length = 0;

    var numMatched = 0;
    var numAdded = 0;
    var optionsOfType = this.allOptions[controller.value];
    if (optionsOfType){
        for (var i = 0; i < optionsOfType.length && numAdded < this.maxValues+1; i++) {
            var option = optionsOfType[i];

            if (existing && this.selectedOptions[option.value]){
                numMatched++;
                continue;
            }

            var match =
                !option.searchValue
                || option.searchValue.length == 0
                || option.searchValue.indexOf(searchValue) == 0
                || option.searchValue.indexOf(' ' + searchValue) > -1;

            if (match){
                if (numAdded < this.maxValues){
                    targetField.options[numAdded] = option;
                }
                numMatched++;
                numAdded++;
            }
        }
    }

    var tooManyValues = numMatched > this.maxValues;
    this.showErrorMessage(tooManyValues);

    if (targetField.options.length == 0) {
        targetField.options[0] = new Option(LC.getLabel("SelectElement", "Required"), '000000000000000');
    }

}

// does a "search" by posting back to the server.
SelectFilterElement.prototype.doSearchServer = function() {
    var form = document.forms[SelectFilterElement.FORMNAME];
    
    // DuelingListBoxesElement may set javascript to be executed
    // on the form.onsubmit(), so we call it before we submit.
    if (form.onsubmit){
        form.onsubmit();
    }

    form.submit();
}

SelectFilterElement.FORMNAME = EditPageConstants.pEDIT_PAGE

SelectFilterElement.prototype.handleKeyDown = function(evt) {
    evt = getEvent(evt);
    // Enter key
    if (evt.keyCode == 13 || evt.which == 13) {
        this.queueSearch();
        return false;
    } else {
        this.searchStringChanged = true;
    }
    return true;
}

SelectFilterElement.prototype.handlePropertyChange = function(){
    if (this.useJsSearch){
        this.queueSearch();
    }
}

SelectFilterElement.prototype.showErrorMessage = function(showMsg, errorMessage) {
    var searchEl = document.getElementById(this.getSearchElementId());
    var err = document.getElementById('error_' + this.targetName);
    if (searchEl && err) {
        if (showMsg) {
            err.style.visibility = 'visible';
            err.innerHTML = errorMessage ? errorMessage : LC.getLabel("Search_Filter", "too_many", this.maxValues, this.maxValues);
        } else {
            err.style.visibility = 'hidden';
        }
    }
}

SelectFilterElement.prototype.filter = function() {

// alert(this.targetName + " " + this.existingName);

    var controller = document.getElementById(this.controllerName);
    var targetField = document.getElementById(this.targetName);
    var searchEl = document.getElementById(this.getSearchElementId());
    if (this.useJsSearch && searchEl && searchEl.value.length != 0) {
        searchEl.value = '';
    }

    targetField.options.length = 0;

    // this value is initialized in selectfilterelement.jsp
    if (SelectFilterElement.prototype.NONE_LABEL) {
        targetField.options[0] = new Option(SelectFilterElement.prototype.NONE_LABEL, '000000000000000');
    }

    var counter = 0;
    var numAdded = 0;
    var optionsOfType = this.allOptions[controller.value];
    if (optionsOfType){

        // if there's a set of already-selected options, then we test
        // against that set before adding them to the target.
        var testForAlreadySelected = this.existingName;

        if (testForAlreadySelected){
            this.initSelectedOptionsFromUi();
        }

        // populating target field based on the options loaded with addOption().
        for (var i = 0; i < optionsOfType.length && (!searchEl || numAdded < this.maxValues+1); i++) {

            var option = optionsOfType[i];

            // If there existing values are there, check against the map before adding
            if (testForAlreadySelected && this.selectedOptions[option.value]) {
                continue;
            }

            counter++;

            // If search exists, then they only get up to maxValues
            if (!searchEl || numAdded < this.maxValues) {
                targetField.options[targetField.options.length] = option;
                numAdded++;
            }
        }

    }

    var tooManyValues = counter > this.maxValues;
    this.showErrorMessage(tooManyValues);

    if (targetField.options.length == 0) {
        targetField.options[0] = new Option(LC.getLabel("SelectElement", "Required"), '000000000000000');
    }
}

// After every change, we re-initialize the map so we can have fast lookup on it
SelectFilterElement.prototype.initSelectedOptionsFromUi = function() {

    if (this.existingName){

        this.selectedOptions = new Array();

        var existing = document.getElementById(this.existingName);
        if (existing){
            for (var i = 0; i < existing.options.length; i++) {
                if (existing.options[i].value.length > 0) {
                    this.selectedOptions[existing.options[i].value] = true;
                }
            }
        }
    }

}

// called from SelectFilterElement.java, when setting bodyOnLoad()
SelectFilterElement.prototype.init = function() {

    // The filter needs to be run at lease once.
    this.filter();

    // If existing is there, make sure we set the onchange event so we can keep track
    // of what is selected.
    if (this.existingName){
        var existing = document.getElementById(this.existingName);
        if (existing){
            existing.selectFilterEl = this;
            existing.onchange = function(){
                this.selectFilterEl.initSelectedOptionsFromUi();
            };
        }
    }

    // Initialize the default controller option
    if (this.controllerOption && this.controllerName){
        var controller = document.getElementById(this.controllerName);
        if (controller.options != null && controller.options != undefined) {
            for (var i = 0; i < controller.options.length; i++) {
                if (controller.options[i].value == this.controllerOption) {
                    controller.options[i].selected = true;
                }
            }
        }
    }

    // Initialize the default target option
    if (this.targetOption){
        var targetField = document.getElementById(this.targetName);
        for (var i = 0; i < targetField.options.length; i++) {
            if (targetField.options[i].value == this.targetOption) {
                targetField.options[i].selected = true;
            }
        }
    }

}

// name as defined in SelectFilterElement.getJavascriptVarName().
SelectFilterElement.prototype.getJavascriptVarName = function(){
    return this.targetName + 'Var';
}

// filtering the drop-down based on the controller is really just showing
// the right corresponding drop-down and hiding the others.
SelectFilterElement.prototype.filterDropdown = function(name, currTypeSelect) {
    var selected = currTypeSelect.selectedIndex;
    for (var i = 0; i < currTypeSelect.options.length; i++){
        var option = currTypeSelect.options[i].value;
        var optionList = name + '_' + option;
        var currSelect = document.getElementById(optionList);
        if (i == selected){
            currSelect.style.display = 'inline';
        } else {
            currSelect.style.display = 'none';
        }
    }
}

SelectFilterElement.prototype.moveLeft = function() {
    this.filter();
}

SelectFilterElement.prototype.beforeMoveRight = function() {
    this.itemAdded = true;
}

/*
 * @author apalke
 * @since 156
 *
 * Shared functions used by the apex calendars
 */

function CalFunctions(){};

CalFunctions.listviewComponentId = null;

CalFunctions.setListviewComponentId = function(id) {
    CalFunctions.listviewComponentId = id;
}

CalFunctions.isListviewPage = function() {
    return CalFunctions.listviewComponentId != null && CalFunctions.listviewComponentId.length != 0;
}

CalFunctions.returnUrlProvider = function() {
    if (CalFunctions.isListviewPage()) {
        var u = ListViewport.instances[CalFunctions.listviewComponentId].retURL;
        if (u != null) {
            return encodeURIComponent(u);
        }
    }
    return window.sfdcPage.getHrefAsRetURL();
}

// used by + links on weekly
CalFunctions.fixAddItemLink = function(link) {
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        link.href = CalFunctions.mungeRetUrl(link.href);
    }
}

// used by click and create full edit link
CalFunctions.fixReturnUrl = function(url) {
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        return CalFunctions.mungeRetUrl(url);
    }
    return url;
}

// used by event hover edit button
CalFunctions.fixReturnUrlAndNavigateToUrl = function(url) {
    var newUrl = url;
    // only need to munge urls on the listview page
    if (CalFunctions.isListviewPage()) {
        newUrl = CalFunctions.mungeRetUrl(url);
    }
    navigateToUrl(newUrl);
}

CalFunctions.mungeRetUrl = function(url) {
    var retUrl = CalFunctions.returnUrlProvider();
    var linkUri = QueryString.getURI(url);
    var linkQs = QueryString.createQueryString(url);
    // if it's a recordtype link, we need to change the retURL in save_new_url param
    var saveNewUrl = linkQs.get(EditPageConstants.pSAVE_NEW_URL);
    if (saveNewUrl != null) {
        // replace the retURL value in save_new_url
        var snUri = QueryString.getURI(saveNewUrl);
        var snQs = QueryString.createQueryString(saveNewUrl);
        snQs.remove(UiData.pRET_URL);
        snQs.add(UiData.pRET_URL, decodeURIComponent(retUrl));
        // replace the save_new_url value in link
        linkQs.remove(EditPageConstants.pSAVE_NEW_URL);
        linkQs.add(EditPageConstants.pSAVE_NEW_URL, snUri + snQs.toString());
    }
    // replace the retURL in link
    linkQs.remove(UiData.pRET_URL);
    linkQs.add(UiData.pRET_URL, decodeURIComponent(retUrl));
    return linkUri + linkQs.toString();
}

//Called when re-rendering is completed
CalFunctions.onCompleteRerender = function() {
	if(InlineScheduler.scheduler != undefined && InlineScheduler.scheduler != null) {
		InlineScheduler.scheduler.postRefreshCalendar();
	}
	Hover.clearHovers();
}

//Actions to be performed before the DOM update when refreshing the calendar
CalFunctions.onBeforeDOMUpdate = function() {
	Hover.clearHovers();
}

function LMACheckboxesManager() {
	var self = this;
	
	this.radios = document.getElementsByName(DeveloperSettings.LICENSE_MGR_CHOICE_STR);
	
	this.divNames = [];
	for (var i = 0; i < arguments.length; i++){
		this.divNames[i] = arguments[i];
	}
	
	this.onClickHandler = function(e){
		self.setVisibility(getEventTarget(getEvent(e)).value);
	}
	
	for (var i = 0; i < this.radios.length; i++){
		addEvent(this.radios[i], 'click', this.onClickHandler, false);
		if (this.radios[i].checked){
			this.setVisibility(this.radios[i].value);
		}
	}
}

LMACheckboxesManager.prototype.setVisibility = function(radioName){
	for (var i = 0; i < this.divNames.length; i++){
		document.getElementById(this.divNames[i] + DeveloperSettings.DIV_SUFFIX).style.display = 
			(this.divNames[i] === radioName ? 'block' : 'none');
	}
}
/*
 * @author ldelascurain
 * @since 150
 *
 */

function FieldTreeNode( key, isLeaf, children, labelName, showLabel, attributes) {
    this.key = key;
    this.isLeaf = isLeaf;
    this.labelName = labelName;
    this.showLabel = showLabel;
    this.attributes = attributes;
    if (children)
	    this.setChildren(children);
}

FieldTreeNode.prototype.setChildren = function(children){
	this.isLeaf = false;
	this.children = children;
	for (var i=0;i<children.length;i++){
    	children[i].parent = this;
    }
}

FieldTreeNode.prototype.getLabelToInsert = function(ignoreShowLabel){
	
    if (!(this.parent && (this.parent.showLabel || ignoreShowLabel)))
        return this.key;
    return this.parent.getLabelToInsert(ignoreShowLabel) + "." + this.key;
}

FieldTreeNode.prototype.getExtraAttributes = function(){

	var attributeArr = ["<table class='fieldPickerAttributeTable'>"];
	for (var key in this.attributes){
		attributeArr.push("<tr><td class='fieldPickerAttributeCategory'>");
		attributeArr.push(key);
		attributeArr.push("&nbsp;")
		attributeArr.push(this.attributes[key]);
		attributeArr.push("</td></tr>");
	}
    attributeArr.push("</table>");

    return attributeArr.join("");
}
/**
 * MRU hover detail object.
 * @author mooney
 * @since 146
 */
function MRUHoverDetail(id) {
    this.id = id;
    this.mruItem = getElementByIdCS("mru" + id);
    this.hover = document.createElement("div");
    this.hover.id = id + "Hover";
    this.hover.className = "mruHoverDetail";
    this.hover.innerHTML = "<div class=\"bPageBlock secondaryPalette\"><div class=\"pbBody\">" + LC.getLabel("Global", "loading") + "</div></div>";
    this.mruItem.appendChild(this.hover);
    this.originalClass = this.mruItem.className;
    var width = this.mruItem.offsetWidth;
    // IE6 calculates the width incorrectly, add in 30 pixels for the mruIcon and its margin
    if (this.mruItem.currentStyle && XBrowser.userAgent.isIE6) {
       width -= 30;
    }
    this.hover.style.left = width + "px";
    this.hover = new iframeShim(this.hover);
    this.fadingOut = null;
    this.fadingIn = null;
    this.loaded = false;
}

MRUHoverDetail.SHOW_DELAY = 800;
MRUHoverDetail.HIDE_DELAY = 400;
// the URL for bulk loading all the MRU hovers
MRUHoverDetail.loaderURL = null;
// boolean for if the request has been sent already
MRUHoverDetail.sentRequest = false;
// response from the bulk loader servlet
MRUHoverDetail.response = null;
// map from id to hover object
MRUHoverDetail.hovers = {};
// id of the currently open hover
MRUHoverDetail.openHover = null;

// static function to retrieve a hover detail using a 15 char ID
MRUHoverDetail.getHover = function(id) {
    if (MRUHoverDetail.hovers[id]) {
        return MRUHoverDetail.hovers[id];
    }
    var hover = new MRUHoverDetail(id);
    MRUHoverDetail.hovers[id] = hover;
    return hover;
}

// static function to load the hover details
MRUHoverDetail.bulkLoad = function() {
    if (!MRUHoverDetail.sentRequest && MRUHoverDetail.loaderURL != null) {
        MRUHoverDetail.sentRequest = true;
        XBrowser.getHttpResponse(MRUHoverDetail.loaderURL,
            function(request) {
                MRUHoverDetail.response = request.responseText;
                // if a hover detail is already open then load it now
                if (MRUHoverDetail.openHover != null) {
                	MRUHoverDetail.hovers[MRUHoverDetail.openHover].load();
                }
            },
            function(request) {
                MRUHoverDetail.response = request.responseText;
                if (MRUHoverDetail.openHover != null) {
                	MRUHoverDetail.hovers[MRUHoverDetail.openHover].load();
                }
            }
        );
    }
}
// show the hover detail
MRUHoverDetail.prototype.show = function() {
    if (this.fadingOut) {
        clearTimeout(this.fadingOut);
        this.fadingOut = null;
	} else {
        var self = this;
	    this.fadingIn = setTimeout( function() { self.showNow(); }, MRUHoverDetail.SHOW_DELAY);
    }
}

MRUHoverDetail.prototype.showNow = function() {
    if (!MRUHoverDetail.sentRequest) {
    	if (MRUHoverDetail.loaderURL != null) {
            MRUHoverDetail.bulkLoad();
    	} else {
    		// we haven't loaded, and we have no URL to load from, so don't display anything.
    		// onunload should null out the URL, so this is mostly to prevent sending a request after
    		// the user navigates away from this page
    		return;
    	}
    }
	MRUHoverDetail.openHover = this.id;
	if (!this.loaded && MRUHoverDetail.response != null) {
		this.load();
	}
    this.hover.setStyle("display", "block");
    if (this.mruItem.currentStyle && XBrowser.userAgent.isIE6) {
        // something wrong with the offsetLeft calc for this in IE6, override it manually for now
        this.hover.iframe.style.left = this.hover.div.style.left;
    }
    this.mruItem.className = this.originalClass + " secondaryPalette";
    this.fadingIn = null;
}

// hide the hover detail
MRUHoverDetail.prototype.hide = function(id) {
    if (this.fadingIn) {
        clearTimeout(this.fadingIn);
        this.fadingIn = null;
    } else {
        var self = this;
        this.fadingOut = setTimeout(function() { self.hideNow(); }, MRUHoverDetail.HIDE_DELAY);
    }
}

MRUHoverDetail.prototype.hideNow = function() {
	MRUHoverDetail.openHover = null;
    this.hover.setStyle("display", "none");
    this.mruItem.className = this.originalClass;
    this.fadingOut = null;
}

// loads the mini detail from the responseText
MRUHoverDetail.prototype.load = function() {
    var startTag = "<" + this.id + ">";
    var endTag = "</" + this.id + ">";
    var start = MRUHoverDetail.response.indexOf(startTag);
    var end = MRUHoverDetail.response.indexOf(endTag);
    if (start != -1 && end != -1) {
    	this.hover.div.innerHTML = MRUHoverDetail.response.slice(start + startTag.length, end);
    	Util.evalScriptsUnderElement(this.hover.div);
    	this.loaded = true;
    }
}

/*
 * @author pburstein
 * @since 150
 * Lookup input element
 *
 */

function LookupElement() {
    var self=this;
    this.lookupPick = function (formName, parentIdElementName, parentEditElementName, relatedFieldName, id, display, relatedFieldValue, extraNameElementName) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPick(formName, parentIdElementName, parentEditElementName, relatedFieldName, id, display, relatedFieldValue, extraNameElementName);
    }
    
    this.lookupPick2 = function(formName, parentIdElementName, parentEditElementName, id, display, extraNameElementName, extraName, extraIdElementName, extraId, allowOverwrite) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPick2(formName, parentIdElementName, parentEditElementName, id, display, extraNameElementName, extraName, extraIdElementName, extraId, allowOverwrite)
    }
    this.lookupPhonePick = function(parentId, newValue) {
        setTimeout(function() { self.closeLookup(); }, 1);
        lookupPhonePick(parentId, newValue)
    }
}

LookupElement.prototype.openLookup = function(baseURL, width, modified, searchParam) {
    if (modified == '1') baseURL = baseURL + searchParam;
    this.initOverlay(baseURL).show();
}

LookupElement.prototype.closeLookup = function() {
    this.getOverlay().hide();
    this.redirectIframe(IFrameElement.BLANK_SRC);
}

LookupElement.prototype.getOverlay = function() {
    return sfdcPage.getDialogById(LookupInputElement.DIALOG_ID);
}

LookupElement.prototype.redirectIframe = function(url) {
    this.getOverlay().getContentElement().firstChild.src = url;
}

LookupElement.prototype.initOverlay = function (baseURL) {
    var ret = this.getOverlay();
    if (ret) {
        this.redirectIframe(baseURL);
    } else {
        var iframeHtml=[]
        iframeHtml.push('<iframe ');
        iframeHtml.push('src="');
        iframeHtml.push(baseURL);
        iframeHtml.push('" class="pageMaskIFrame" scrolling="no" ');
        iframeHtml.push('id="');
        iframeHtml.push(LookupInputElement.LOOKUP_IFRAME);
        iframeHtml.push('" name="');
        iframeHtml.push(LookupInputElement.LOOKUP_IFRAME);
        iframeHtml.push('"></iframe>');
        iframeHtml = iframeHtml.join('');
    
        ret = new FunctionalDialog(LookupInputElement.DIALOG_ID, true, LC.getLabel('Lookup', 'Title'));
        ret.setWidth(900);
        ret.setMaxHeight(700);
        ret.hideSummaryElement();
        ret.clearButtons();
        sfdcPage.registerDialog(ret);
        ret.setContentInnerHTML(iframeHtml);
    }
    return ret;
}


function EncryptedTextInputElement(id, maxLength, isMasked){
	if (!isMasked) return;
	this.maxLength = maxLength;
	this.element = getElementByIdCS(id);
	if (!this.element) return;
	
	this.wasCleared = false;
	this.origValue = this.element.value;
	
	var self = this;
	
	this.handleOnFocus = function(e){
		if (self.wasCleared){
			return;
		}
		self.element.select();
	}
	
	this.handleKey = function(e){
		if (!self.wasCleared){
			var code = getEvent(e).keyCode;
			if (!(code === KEY_ENTER || code === KEY_TAB || code === KEY_PAGEUP || code === KEY_PAGEDOWN)){
				self.element.value = "";
				self.element.maxLength = self.maxLength;
				self.wasCleared = true;
			}
		}
	}
	
	this.handleBlur = function(e){
		if (self.element.value === self.origValue){
			self.wasCleared = false;
		}
	}
	
	addEvent(this.element, 'focus', this.handleOnFocus, true);
	addEvent(this.element, 'blur', this.handleBlur, true)
	addEvent(this.element, 'keypress', this.handleKey, true);
}
function DebugTimer(domId, leftLoc, title) {
    this.domId = domId;
    this.leftLoc = leftLoc;
    this.title = title;
}

DebugTimer.prototype.resetTimer = function () {
    this.timepoint(null, true);
}

DebugTimer.prototype.timepoint = function (label, reset) {    
    if (!this.timer || reset) {
        this.timer = new Date();
        this.times = [];
    } else {
        var start = this.timer;
        this.timer = new Date();
        var elapsed = this.timer.getTime() - start.getTime();
        this.times.push({label: label, elapsed: elapsed});
    }
}

DebugTimer.prototype.outputTimes = function() {
    if (!this.times)
        return;
        
    var total = 0;
    var html = [];
    html.push("==========<br/>");
    html.push(this.title);
    html.push("<br/>");
    html.push("==========<br/>");
    for (var i=0; i<this.times.length; i++) {
        if (typeof(this.times[i].elapsed)=="number") {
            html.push(this.times[i].elapsed);
            html.push("ms");
            var tabnum = 8-(this.times[i].elapsed+"").length
            for (var j=0; j<tabnum; j++) {
                html.push("&nbsp;");
            }
            html.push(this.times[i].label);
            html.push("<br/>");
            total += this.times[i].elapsed;
        } else {
            html.push(this.times[i]);
            html.push("<br/>");
        }
    }
    html.push("----------<br/><b>");
    html.push(total);
    html.push("ms");
    var tabnum = 8-(total+"").length
    for (var j=0; j<tabnum; j++) {
        html.push("&nbsp;");
    }
    html.push("TOTAL TIME</b>");
    
    if (!this.debugDiv) {
        this.debugDiv = document.createElement('div');
        this.debugDiv.id = this.domId + "_debugDiv";
        this.debugDiv.style.position = "absolute";
        this.debugDiv.style.top = "0px";
        this.debugDiv.style.left = this.leftLoc + "px";
        this.debugDiv.style.border = "2px solid red";
        this.debugDiv.style.margin = "3px";
        this.debugDiv.style.padding = "3px";
        this.debugDiv.style.backgroundColor = "white";
        this.debugDiv.style.fontFamily = "Courier New, Courier, monospace";
        this.debugContent = document.createElement('div');
        var toggle = document.createElement('input');
        toggle.type = "button";
        toggle.value = "Show/Hide Debug Log";
        toggle.className = "btn";
        var debugContentDiv = this.debugContent;
        toggle.onclick = function() {
            if (debugContentDiv.style.display == "none") {
                debugContentDiv.style.display = "";
            } else {
                debugContentDiv.style.display = "none";
            }
        };
        this.debugDiv.appendChild(toggle);
        var outputTimes = document.createElement('input');
        outputTimes.type = "button";
        outputTimes.value = "Output Times";
        outputTimes.className = "btn";
        var self = this;
        outputTimes.onclick = function() {
            self.outputTimes();
        };
        this.debugDiv.appendChild(outputTimes);
        this.debugDiv.appendChild(this.debugContent);
        document.body.appendChild(this.debugDiv);
    }
    this.debugContent.innerHTML = html.join('');
}

DebugTimer.prototype.toggle = function() {
    if (!this.debugContent) {
        return;
    }
    
    if (this.debugContent.style.display == "none") {
        this.debugContent.style.display = "";
    } else {
        this.debugContent.style.display = "none";
    }
}
/**
 * This class handles auto complete functionality on the tag header element.
 * It grabs _all_ the tags for the current user from LookupTagsPage and caches this list.
 * Given the current count limit on private tags (500) this is not a problem, but in the
 * future we might want to be more selective about what we grab.
 *
 * @author mpaksoy
 * @since 150
 * based on AutoComplete.js by rchoi
 */

/**
 * @param elem text area element used for auto complete
 * NOTE: this element needs a DOM id
 * @param callback keypress event handler callback. Auto complete needs priviledged access to
 * the keypress event to grab the tab/enter keys, it will pass the event on as necessary.
 */
function TagAutoComplete(elem, tagMode, callback) {
    this.element = elem;
    this.id = this.element.id;
    this.tagMode = tagMode;

    this.recordHeight = 18;

    this.selection = false;
    this.keyPressCallback = callback;

    // EVENT HANDLERS
    var self = this;
    addEvent(this.element, 'keyup', function(e) { self.onKeyUp(e); });
    addEvent(this.element, 'keydown', function(e) { self.captureKeyPress(e); });
    addEvent(this.element, 'keypress', function(e) { self.captureKeyPress(e, true); });
    addEvent(this.element, 'blur', function(e) { self.onBlur(e); });
    addEvent(window, 'resize', function(e) { self.resizeLocationUpdater(e); });

    window[this.id + TagAutoComplete.MOUSE_OVER_HANDLER] = function(i) { self.updateSelection(i); };
}

// STATIC CONSTANTS
TagAutoComplete.MOUSE_OVER_HANDLER = '_autoCompleteMouseOverHandler';
TagAutoComplete.BOX_ID = '_autoCompleteBoxId';
TagAutoComplete.FRAME_ID = '_autoCompleteFrameId';
TagAutoComplete.ROW_ID = '_autoCompleteRowId';
TagAutoComplete.BOX_CSS_CLASS = 'autoCompleteBox';
TagAutoComplete.ROW_CSS_CLASS = 'autoCompleteRow';
TagAutoComplete.SELECTED_ROW_CSS_CLASS = 'autoCompleteSelectedRow';
TagAutoComplete.MORE_ROW_CSS_CLASS = 'autoCompleteMoreRow';
TagAutoComplete.MIN_LENGTH_THRESHOLD = 1;
TagAutoComplete.MAX_SUGGESTIONS = 15;
TagAutoComplete.EMPTY = /^\s*$/;

// INSTANCE METHODS

/**
 * Set the function to call when text is entered to see if text area needs to
 * be resized.
 */
TagAutoComplete.prototype.setResizer = function(callback) {
    this.resizeCallback = callback;
}

/**
 * Call the resize handler and move auto complete box if necessary.
 */
TagAutoComplete.prototype.resizeTextArea = function() {
    if (this.resizeCallback && this.resizeCallback()) { // if resized
        this.updateBoxLocation();
    }
}

/**
 * Display the auto-complete box containing the given set of suggestions.
 * @param records array of suggestions
 */
TagAutoComplete.prototype.displayResults = function(records) {
    if (!records || !(records instanceof Array)) return;
    if (records.length == 0) {
        if (this.box) {
            this.doClear();
        }
        return;
    }

    var html = [];
    html.push("<table width='100%' cellpadding='0' cellspacing='0' border='0'>");
    for (var i = 0; i < records.length; i++){
        if (i >= TagAutoComplete.MAX_SUGGESTIONS) {
            html.push("<tr><td>");
            html.push("<div ");
            html.push("class='" + TagAutoComplete.MORE_ROW_CSS_CLASS+"'");
            html.push(">");
            html.push(LC.getLabel('TagHeader','auto_complete_more'));
            html.push("</div>");
            html.push("</td></tr>");
            break;
        }

        var record = records[i];
        html.push("<tr><td>");
        html.push("<div ");
        html.push("onmouseover='");
        html.push("window."+this.id+TagAutoComplete.MOUSE_OVER_HANDLER+"("+i+");'");
        html.push("class='"+TagAutoComplete.ROW_CSS_CLASS+"' ");
        html.push("id='"+this.getRowId(i)+"'>");
        html.push("<span>");
        html.push(record);
        html.push("</span>");
        html.push("</div>");
        html.push("</td></tr>");
    }
    html.push("</table>");

    var recordsShown = (records.length > TagAutoComplete.MAX_SUGGESTIONS) ?
                        TagAutoComplete.MAX_SUGGESTIONS + 1: records.length;
    if (!this.box){ // need to create auto complete box
        // IE6 returns the wrong element position if we call getObjX() right after calling makeBox() so we save coordinates from before.
        var y = getObjY(this.element) + this.element.offsetHeight;
        var x = getObjX(this.element);
        this.makeBox();
        this.moveBox(y, x);
    }
    this.box.div.innerHTML = html.join('');
    this.showBox(true);
    this.updateSelection(0); // pick the first one by default
}

TagAutoComplete.prototype.resizeLocationUpdater = function() {
    if (this.box) // box already created
        this.updateBoxLocation();
}

TagAutoComplete.prototype.updateBoxLocation = function() {
    this.moveBox(getObjY(this.element) + this.element.offsetHeight, getObjX(this.element));
}

/**
 * Connects to the servlet to grab the list tags for the current user.
 * This list is only grabbed once, and cached.
 */
TagAutoComplete.prototype.doLookup = function() {
    if (this.IS_PROCESSING) return;
    if (this.cache || this.doneCaching) return;

    var qs = new QueryString("");
    qs.add(TagConstants.pTAG_SCOPE_MODE, this.tagMode);
    var servlet = UserContext.getUrl(TagConstants.LOOKUP_TAGS_PAGE) + qs.toString();
    this.IS_PROCESSING = true;
    var self = this;

    var requestHandler = function(request) {
        var resp = request.responseText;
        if (resp) {
            self.cache = resp.split(', ');
            self.filterDisplayResults();
        }
        self.doneCaching = true;
        self.IS_PROCESSING = false;
    }

    XBrowser.getHttpResponse(servlet, requestHandler);
}

/**
 * Hide the suggestion box and deselection suggestion.
 */
TagAutoComplete.prototype.doClear = function(){
    this.selection = false;
    this.results = false;
    this.lastSearched = false;
    this.showBox(false);
}

/**
 * Update the selected suggestion. Updates highlighing on suggestion rows accordingly.
 */
TagAutoComplete.prototype.updateSelection = function(index) {
    if (this.getRow(this.selection)) { // if something previously selected, unselect
        this.getRow(this.selection).className = TagAutoComplete.ROW_CSS_CLASS;
    }
    var row = this.getRow(index);
    if (!row) return;
    this.selection = index;
    row.className = TagAutoComplete.SELECTED_ROW_CSS_CLASS;
}

/**
 * Return the last word in the comma seperated list of tags from the text area.
 * Trims the whitespace around this element.
 */
TagAutoComplete.prototype.getCurrentWord = function() {
    if (!this.element || !this.element.value) return;
    var tags = this.element.value.split(",");
    return tags[tags.length-1].replace(/^\s+|\s+$/g,""); // trim spaces before/after word
}

/**
 * Search the cache for tags starting with the current word (see getCurrentWord)
 * If the new search string matches beginning of the last search string, it will
 * do an incremental search on the results of the last search
 * If not, it will do a brute force search.
 *
 * With 500 tags, this is not a very big issue, but might become an issue in the future.
 * Might want to use a data structure like a trie to  easily narrow down results and
 * backtrack as necessary.
 */
TagAutoComplete.prototype.filterDisplayResults = function() {
    if (!this.cache) {
        this.results = false;
        return; // need stuff in the cache
    }
    var val = this.getCurrentWord();
    if (this.results && this.lastSearched && TagAutoComplete.isMatch(this.lastSearched, val)) {
        var newresults = [];
        for (var i = 0; i < this.results.length; i++) {
            var string = this.results[i];
            if (TagAutoComplete.isMatch(val, string)) {
                newresults.push(this.results[i]);
            }
        }
        this.results = newresults;
    } else {
        this.results = [];
        for (var i = 0; i < this.cache.length; i++) {
            var string = this.cache[i];
            if (TagAutoComplete.isMatch(val, string)) {
                this.results.push(string);
            }
        }
        this.results.sort(function(a,b) { // case insensitive compare
                var aNorm = a.toLowerCase();
                var bNorm = b.toLowerCase();
                if (aNorm == bNorm) return 0;
                return (aNorm > bNorm) ? 1 : -1;
            });
    }

    this.lastSearched = val;
    this.displayResults(this.results);
}

/**
 * Get the id of the suggestion row with index
 */
TagAutoComplete.prototype.getRowId = function(index) {
    return this.id + TagAutoComplete.ROW_ID + index;
}

/**
 * Get the DOM node for the suggestion row
 */
TagAutoComplete.prototype.getRow = function(index) {
    return document.getElementById(this.getRowId(index));
}

// EVENTS (called from within the context of this class)

/**
 * Called by the (yes, you guessed it) key up listener.
 * Calls the enter/tab/esc keys accordingly, or updates the suggestions for the
 * new string.
 */
TagAutoComplete.prototype.onKeyUp = function(event){
    if (!event || !event.keyCode) return;

    this.captureKeyPress(event);

    var inIME = this.inKeyIME;
    this.inKeyIME = false;

    var val = this.element.value;
    if (this.IS_PROCESSING) {
        return;
    } else if (!inIME && TagAutoComplete.isComplete(event)) {
        this.complete();
        return;
    } else if (TagAutoComplete.isNavigation(event)) {
        this.handleNav(event);
        return;
    } else if (TagAutoComplete.isEscape(event) || !this.checkCursorAtEnd()) {
        this.doClear();
        return;
    } else if (TagAutoComplete.isIgnore(event)) {
        return;
    } else if (inIME && event.keyCode != KEY_ENTER) {
        return;
    }

    if (!this.cache) {
        this.doLookup();
    }

    this.resizeTextArea();

    if (val != null && val.length >= TagAutoComplete.MIN_LENGTH_THRESHOLD){
        this.filterDisplayResults();
    } else if (val == null || val.length < TagAutoComplete.prototype.MIN_LENGTH_THRESHOLD || TagAutoComplete.EMPTY.exec(val)){
        this.doClear();
    }
}

/**
 * Auto-complete with the current suggestion: replace the partially entered
 * suggestion with the text of the chosen suggestion and close suggestion box.
 */
TagAutoComplete.prototype.complete = function() {
    if (this.selection === null || this.selection === false) return;
    if (this.selection < 0 || this.selection >= this.results.length) return;

    var suggestion = this.results[this.selection];
    this.completeText(suggestion);
    this.doClear();
    this.element.focus();

    if (XBrowser.userAgent.isSafari) {
        this.element.selectionStart = this.element.value.length;
        this.element.selectionEnd = this.element.value.length;
    }
}

/**
 * Handles the string substitution for completing the partially typed
 * tag with the chosen suggestion.
 */
TagAutoComplete.prototype.completeText = function(text) {
    var values = this.element.value.split(',');
    if (values.length <= 1) {
        values = [text];
    } else {
        values[values.length-1] = ' '+text;
    }
    this.element.value = values.join(',')+', ';
    this.resizeTextArea();
}

/**
 * Called when focus moves away from our text area. Closes the suggestion box.
 * There's a delay associated with this to allow clicks to be processed on the
 * suggestion box, otherwised it's closed before the event can be caught.
 */
TagAutoComplete.prototype.onBlur = function() {
    var self = this;
    var handler = function() { self.doClear(); }
    setTimeout(handler, 200);
}

/**
 * Handle the up and down navigation keys. Wraps around the suggestion box (going up at the top
 * will go back to the bottom).
 */
TagAutoComplete.prototype.handleNav = function(event) {
    if (!event || !event.keyCode) return;
    if (!this.results || (this.results.length == 0)) return;

    var lastIndex = (this.results.length > TagAutoComplete.MAX_SUGGESTIONS) ?
                        TagAutoComplete.MAX_SUGGESTIONS - 1: this.results.length - 1;

    var keyCode = event.keyCode;
    var newSelect = this.selection;
    if (keyCode == KEY_ARROW_U) {
        if (newSelect === false) { // nothing selected yet
            newSelect = lastIndex;
        } else {
            newSelect--;
        }
    } else if (keyCode == KEY_ARROW_D) {
        if (newSelect === false) {
            newSelect = 0;
        } else {
            newSelect++;
        }
    }

    if (newSelect > lastIndex) {
        newSelect = 0;
    } else if (newSelect < 0) {
        newSelect = lastIndex;
    }

    this.updateSelection(newSelect);
}

// BOXES
TagAutoComplete.prototype.makeBox = function() {
    // div for the contents
    this.box = document.createElement("div");
    this.box.id = this.id+TagAutoComplete.BOX_ID;
    this.box.className = TagAutoComplete.BOX_CSS_CLASS;
    document.body.appendChild(this.box);
    // add event handler
    var self = this;
    addEvent(this.box, 'click', function() { self.complete(); });
    this.box = new iframeShim(this.box);
    return this.box;
}

TagAutoComplete.prototype.moveBox = function(top, left){
    if (this.box){
        this.box.setStyle('top', top + "px");
        this.box.setStyle('left', left + "px");
    }
}

TagAutoComplete.prototype.showBox = function(isVisible){
    var disp = isVisible ? "block" : "none";

    if (this.box){
        this.box.setStyle('display', disp);
    }
}

/**
 * Prevent the navigation and tab/enter keys from being handled
 * @param event event object for the key/up/down/press
 * @param boolean set to true, if you want to execute keyPressCallback as necessary
 */
TagAutoComplete.prototype.captureKeyPress = function(event, isKeyPress) {
    if (!event || (!event.charCode && !event.keyCode)) {
        return;
    }
    var code = event.charCode ? event.charCode : event.keyCode;
    // If we get a KEY_PROCESS in a keydown, then the user is using
    // IME to input characters like Japanese Hiragana, and therefore
    // we'll need to ignore the ending enter as it's part of character entry
    // http://bugforce.soma.salesforce.com/bug/bugDetail.jsp?id=100000000000qY0
    if (!isKeyPress && code == KEY_PROCESS) {
        this.inKeyIME = true;
    }
    if (this.selection === false) {
        if (isKeyPress && this.keyPressCallback) this.keyPressCallback(event);
        return;
    }

    if (code == KEY_ENTER || code == KEY_TAB || code == KEY_ARROW_U || code == KEY_ARROW_D || code == KEY_ESC) {
        TagAutoComplete.stopBubble(event);
    }
}

/**
 * Return true if there is no text after cursor in input element (excluding spaces).
 * If 1 or more characters are selected, returns false.
 * Note: Behavior is undefined if the element does not have focus, so make sure it does.
 */
TagAutoComplete.prototype.checkCursorAtEnd = function() {
    if (!this.element) return false;
    var afterCaret;
    if (XBrowser.userAgent.isIE) {
        var selRange = document.selection.createRange().duplicate();
        if (selRange.text && (selRange.text.length > 0)) return false; // text selected
        var textRange = selRange.duplicate();
        textRange.moveToElementText(this.element);
        try { // setEndPoint is known throw exceptions on bad days
            selRange.setEndPoint("EndToEnd", textRange);
            afterCaret = selRange.text;
        } catch (e) {
            return true;
        }
    } else { // life's so much better with Firefox
        if (this.element.selectionStart != this.element.selectionEnd) return false; // text selected
        afterCaret = this.element.value.substring(this.element.selectionStart);
    }
    return TagAutoComplete.EMPTY.exec(afterCaret);
}

// STATIC METHODS
TagAutoComplete.isNavigation = function(event){
    var code = event.keyCode;
    return (code == KEY_ARROW_U || code == KEY_ARROW_D);
}

// 9 is TAB; 16 is SHIFT-TAB
TagAutoComplete.isIgnore = function(event){
    var code = event.keyCode;
    return (code == 16 || (code >= 33 && code <= 46) || (code >= 112 && code <= 123));
}

TagAutoComplete.isEscape = function(event){
    var code = event.keyCode;
    return code == KEY_ESC;
}

/**
 * Tab/enter keys execute auto complete.
 * Checks if the current keystroke is tab or enter.
 */
TagAutoComplete.isComplete = function(event){
    var code = event.keyCode;
    return (code == KEY_ENTER || code == KEY_TAB);
}

/**
 * Return the normalized version of the given tag.
 */
TagAutoComplete.normalize = function(tag) {
    return tag.replace(/\s|-|_/g,"").toLowerCase()
}

/**
 * Return true if substring matches the beginning of string. Case insensitive.
 * Ex. if substring='abc' and string='AbCdef' then this will return true.
 */
TagAutoComplete.isMatch = function(substring, string) {
    if (!substring || !string) return false;
    substring = TagAutoComplete.normalize(substring);
    string = TagAutoComplete.normalize(string);
    if (substring.length > string.length) return false;
    return (string.indexOf(substring) === 0);
}

/**
 * Stops bubbling on the event and prevents default browser behavior at the same time.
 */
TagAutoComplete.stopBubble = function(event) {
    if (XBrowser.userAgent.isIE) {
        event.returnValue = false;
        event.cancelBubble = false;
    } else {
        event.preventDefault();
        event.stopPropagation();
    }
}

/**
 * Class contains JavaScript methods for manipulating dueling lists.
 * TODO there are several static methods here that should eventually be refactored into
 * instance methods.
 *
 * @author mpaksoy
 * @since 150
 *
 */

/**
 * Constructor
 *
 * @param selectionIds Array of selection element ids. These are used to read and restore the selection list
 * contents.
 * @param warnId
 * @param removeWarnIf Function to call to decide whether to warn the user when removing an option.
 * @param removeWarningtext Warning message to display when removing an option.
 */
function DuelingListBoxesElement(selectionIds, warnId, removeWarnIf, removeWarningText) {
    this.sListIds=selectionIds;
    this.warnDiv=warnId;
    this.removeWarnIf=removeWarnIf;
    this.removeWarningText=removeWarningText;
}

/**
 * Sets a flag to make sure the state is stored only once.
 * Stores state using storeState()
 */
DuelingListBoxesElement.prototype.storeStateOnce = function() {
    if (this.isStored) {
        return;
    }
    this.isStored=true;
    this.storeState();
}

/**
 * Note: use storeStateOnce() to prevent overriding the initial state.
 * Stores the ordering, values and labels of option elements inside all selection lists.
 */
DuelingListBoxesElement.prototype.storeState = function() {
    this.selectContents=new Array();
    for (var i = 0; i < this.sListIds.length; i++) {
        var curSelect = document.getElementById(this.sListIds[i]);
        if (!curSelect) {
            continue;
        }
        this.selectContents[i]=new Array();
        for (var j = 0; j < curSelect.options.length; j++) {
            this.selectContents[i][j]=[curSelect.options[j].text, curSelect.options[j].value];
        }
    }
}

/**
 * Restore selection list contents from stored state.
 */
DuelingListBoxesElement.prototype.resetSelection = function() {
    if (!this.isStored)
        return;

    for (var i=0; i < this.sListIds.length; i++) {
        var curSelect = document.getElementById(this.sListIds[i]);
        if (!curSelect) {
            continue;
        }

        Util.refreshDynamicSelect(curSelect, this.selectContents[i]);
    }
}

/**
 * Displays a warning message using the warnDiv field (should be set using constructor)
 */
DuelingListBoxesElement.prototype.quickWarn = function(message) {
    DuelingListBoxesElement.warning(this.warnDiv, message);
}

/**
 * Removes the warning message using the warnDiv field (should be set using constructor)
 */
DuelingListBoxesElement.prototype.quickUnwarn = function() {
    DuelingListBoxesElement.removeWarning(this.warnDiv);
}

// instMove* methods are wrappers around the corresponding static move* methods that store selection box state on first
// modification
DuelingListBoxesElement.prototype.instMoveDown = function(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage,
        warnDivId) {
    this.storeStateOnce();
    DuelingListBoxesElement.moveDown(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage, warnDivId);
}

DuelingListBoxesElement.prototype.instMoveUp = function(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage,
        warnDivId) {
    this.storeStateOnce();
    DuelingListBoxesElement.moveUp(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage,
            warnDivId);
}

DuelingListBoxesElement.prototype.instMoveBottom = function(sourceSelect, warnDivId) {
    this.storeStateOnce();
    DuelingListBoxesElement.moveBottom(sourceSelect, warnDivId);
}

DuelingListBoxesElement.prototype.instMoveTop = function(sourceSelect, warnDivId) {
    this.storeStateOnce();
    DuelingListBoxesElement.moveTop(sourceSelect, warnDivId);
}


DuelingListBoxesElement.prototype.instMoveOption = function(sourceSelect, targetSelect, keepSourceLabel, unmovableSourceValues,
        unmovableAlertMessages, keepTargetLabel, cannotBeEmpty, cannotBeEmptyMessage, warnDivId) {
    this.storeStateOnce();
    DuelingListBoxesElement.moveOption(sourceSelect, targetSelect, keepSourceLabel, unmovableSourceValues,
        unmovableAlertMessages, keepTargetLabel, cannotBeEmpty, cannotBeEmptyMessage, warnDivId, this.removeWarnIf, this.removeWarningText);
}

DuelingListBoxesElement.prototype.instSaveAllSelected = function(fromSelectArray, toArray, delim, escape, emptyLabel) {
    DuelingListBoxesElement.saveAllSelected(fromSelectArray, toArray, delim, escape, emptyLabel);
}

/**
 * Displays the given warning message in the given warning box.
 *
 * @param warnId warning box div id
 * @param message the inner html of the warn text div is replaced with this
 */
DuelingListBoxesElement.warning = function(warnId, message) {
    if (!warnId) {
        return;
    }
    var warnDiv = document.getElementById(warnId);
    if (warnDiv) {
        warnDiv.innerHTML = LC.getLabel("Global", "colonSeparatedWords", LC.getLabel("Global", "error"), message);
        warnDiv.style.display = "block";
    }
}

/**
 * Removes the warning message from the given warning box div.
 *
 * @param warnId warning box div id
 */
DuelingListBoxesElement.removeWarning = function (warnId) {
    if (!warnId) {
        return;
    }
    var warnDiv = document.getElementById(warnId);
    if (warnDiv) {
        warnDiv.innerHTML = ""
        warnDiv.style.display = "none";
    }
}

DuelingListBoxesElement.moveTop = function(sourceSelect, warnDivId) {

    if (sourceSelect.length > 1) {
        var options = sourceSelect.options;

        // find which ones are selected...
        var selectedIds = new Array ();
        var index = 0;

        for (var i = 0; i < sourceSelect.length; i++) {
            if (options[i].selected) {
                selectedIds[index] = i;
                index++;
            }
        }

        // Move each selected option up to the topmost available
        // position.  The first one in the selected list gets position 0,
        // second one gets position 1, and so on.
        var selId;
        for (var i = 0; i < selectedIds.length; i++) {
            selId = selectedIds[i];
            // delta is how many positions up to move the selected item
            // to get it into the target position, which is position "i"
            delta = selId-i;
            for (var j = 0 ; j < delta; j++) {
                DuelingListBoxesElement.privateMoveUp (options, selId-j);
                options[selId-j].selected = false;
                options[(selId-j)-1].selected = true;
                }
        }

        sourceSelect.focus ();

        // invoke if the Slect Element has local function
        if (sourceSelect["onLocalMoveTop"])
            sourceSelect.onLocalMoveTop();
    }
    DuelingListBoxesElement.removeWarning(warnDivId);
}

DuelingListBoxesElement.moveBottom = function(sourceSelect, warnDivId) {

    if (sourceSelect.length > 1) {
        var options = sourceSelect.options;

        // find which ones are selected...
        var selectedIds = new Array ();
        var index = 0;

        for (var i = 0; i < sourceSelect.length; i++) {
            if (options[i].selected) {
                selectedIds[index] = i;
                index++;
            }
        }

        // move each selected option down - starting from the end
        // of the selected items array, we'll move each item down to
        // the next lowest position (i.e., last one in the array ends up at
        // the very bottom, nth one in the array ends up (array length - n) from
        // the bottom
        // targetPos is position the element is moving to
        var targetPos = sourceSelect.length-1;
        var selId;
        for (var i = selectedIds.length-1; i >= 0 ; i--) {
            selId = selectedIds[i];
            // delta is how much to move down from the current position to get to the target position
            var delta = targetPos-selId;
            for (var j = 0 ; j < delta; j++) {
                DuelingListBoxesElement.privateMoveDown (options, selId+j);
                options[selId+j].selected = false;
                options[(selId+j)+1].selected = true;
                }
            targetPos--;
        }

        sourceSelect.focus ();

        // invoke if the Slect Element has local function
        if (sourceSelect["onLocalMoveBottom"])
            sourceSelect.onLocalMoveBottom();
    }
    DuelingListBoxesElement.removeWarning(warnDivId);
}

/*
 * Do not call this function directly.
 * As it does NO bounds checking.
 * Please use the moveUp or moveTop calls.
 */
DuelingListBoxesElement.privateMoveUp = function(options, index) {
    var newOption = new Option (options[index-1].text, options[index-1].value);
    options[index-1].text = options[index].text;
    options[index-1].value = options[index].value;
    options[index].text = newOption.text;
    options[index].value = newOption.value;
}

/*
 * Do not call this function directly.
 * As it does NO bounds checking.
 * Please use the moveDown or moveBottom calls.
 */
DuelingListBoxesElement.privateMoveDown = function(options, index) {
    var newOption = new Option (options[index+1].text, options[index+1].value);
    options[index+1].text = options[index].text;
    options[index+1].value = options[index].value;
    options[index].text = newOption.text;
    options[index].value = newOption.value;
}

DuelingListBoxesElement.moveDown = function(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage,
        warnDivId) {
    var seenWarn=false;
    if (sourceSelect.length > 1) {
        var options = sourceSelect.options;

        // find which ones are selected
        var selectedIds = new Array ();
        var index = 0;
        if (topSourceValue != null) {
            // make sure we don't move the top value down, unless the second value is the radical value and it's not being moved
            if (topSourceValue == options[0].value && options[0].selected && (options[1].value != radicalValue || options[1].selected)) {
                options[0].selected = false;
                if (unmovableAlertMessage != null) {
                    DuelingListBoxesElement.warning(warnDivId, unmovableAlertMessage);
                    seenWarn=true;
                }
            }
            // when a radical value is specified, also check the second value:
            // second value can't be moved down if it's the topValue
            if (radicalValue && options[1].value == topSourceValue && options[1].selected) {
                options[1].selected = false;
                if (unmovableAlertMessage != null) {
                    DuelingListBoxesElement.warning(warnDivId, nmovableAlertMessage);
                    seenWarn=true;
                }
            }
        }

        for (var i = sourceSelect.length-2; i >= 0; i--) {
            if (sourceSelect.options[i].selected) {
                // add any remaining selected elements to our array of elements to move
                selectedIds[index] = i;
                index++;
            }
        }

        // move each selected element down
        var selId;
        for (var i = 0; i < selectedIds.length; i++) {
            selId = selectedIds[i];
            DuelingListBoxesElement.privateMoveDown (options, selId);
            options[selId].selected = false;
            options[selId+1].selected = true;
        }

        sourceSelect.focus ();

        // invoke if the Slect Element has local function
        if (sourceSelect["onLocalMoveDown"])
            sourceSelect.onLocalMoveDown();
    }
    if (!seenWarn) {
        DuelingListBoxesElement.removeWarning(warnDivId);
    }
}

DuelingListBoxesElement.moveUp = function(sourceSelect, topSourceValue, radicalValue, unmovableAlertMessage,
        warnDivId) {
    if (sourceSelect.length > 1) {
        var options = sourceSelect.options;

        // find which ones are selected...
        var selectedIds = new Array ();
        var index = 0;
        if (topSourceValue != null) {
            // second value can't be moved up if first value is topValue, unless second value is the radical value
            if (options[0].value == topSourceValue && options[1].selected && options[1].value != radicalValue) {
                options[1].selected = false;
                if (unmovableAlertMessage != null) {
                    DuelingListBoxesElement.warning(warnDivId, unmovableAlertMessage);
                    return;
                }
            }
            // when a radical value is specified, apply the same rule to the third value:
            // third value can't be moved up if second value is topValue OR if second value is going to be moved up
            if (radicalValue && options[2].selected && (options[1].value == topSourceValue || options[1].selected)) {
                options[2].selected = false;
                if (unmovableAlertMessage != null) {
                    DuelingListBoxesElement.warning(warnDivId, unmovableAlertMessage);
                    return;
                }
            }
            // notice the return statements:  if any one option cannot be moved up, then
            // do not move up any of the options
        }
        for (var i = 1; i < sourceSelect.length; i++) {
            if (options[i].selected) {
                selectedIds[index] = i;
                index++;
            }
        }

        // move each selected option up
        var selId;
        for (var i = 0; i < selectedIds.length; i++) {
            selId = selectedIds[i];
            DuelingListBoxesElement.privateMoveUp (options, selId);
            options[selId].selected = false;
            options[selId-1].selected = true;
        }

        sourceSelect.focus ();

        // invoke if the Slect Element has local function
        if (sourceSelect["onLocalMoveUp"])
            sourceSelect.onLocalMoveUp();
    }
    DuelingListBoxesElement.removeWarning(warnDivId);
}


DuelingListBoxesElement.moveOption = function(sourceSelect, targetSelect, keepSourceLabel, unmovableSourceValues,
                        unmovableAlertMessages, keepTargetLabel, cannotBeEmpty, cannotBeEmptyMessage, warnDivId, removeWarnIf, removeWarningText) {
	// Adding a warning placeholder for when a user tries to remove the default landing tab in Customize My Tabs.
	if (removeWarnIf && removeWarnIf()){
		if (!((Modal.confirm && Modal.confirm(removeWarningText)) || (!Modal.confirm && window.confirm(removeWarningText))))
			return;
	}

    var seenWarn=false;
    var sourceOptions = sourceSelect.options;

    var canMove;
    var option;

    // find which ones are selected...
    var selectedIds = new Array ();
    var index = 0;
    if (sourceSelect.cannotBeEmpty || cannotBeEmpty) {
        var numSelected = 0;
        for (var i = 0; i < sourceSelect.length; i++) {
            if (sourceSelect.options[i].selected) numSelected++;
        }
        if (numSelected == sourceSelect.options.length) {
            if (sourceSelect.handleEmptyList) {
                sourceSelect.handleEmptyList();
            }
            if (cannotBeEmptyMessage) {
                DuelingListBoxesElement.warning(warnDivId, cannotBeEmptyMessage);
            }
            return;
        }
    }

    for (var i = 0; i < sourceSelect.length; i++) {
        option = sourceOptions[i];
        if (option.selected) {
            canMove = (option.text != keepSourceLabel);
            if (canMove && unmovableSourceValues != null) {
                // make sure we don't move any options defined as unmovable
                for (var j = 0; j < unmovableSourceValues.length; j++) {
                    if (unmovableSourceValues[j] == option.value) {
                        canMove = false;
                        if (unmovableAlertMessages[j] != null) {
                            DuelingListBoxesElement.warning(warnDivId, unmovableAlertMessages[j]);
                            seenWarn=true;
                        }
                        break;
                    }
                }
            }

            // if this option can be moved we add it to our array of elements to move
            if (canMove) {
                selectedIds[index] = i;
                index++;
            } else {
                // if we can't move this option, then unselect it
                option.selected = false;
            }
        }
    }

    // move them over one by one
    var targetOptions = targetSelect.options;
    if (selectedIds.length > 0) {
        targetSelect.selectedIndex = -1;
        for (var i = 0; i < selectedIds.length; i++) {
            option = new Option (sourceOptions[selectedIds[i]].text, sourceOptions[selectedIds[i]].value);
            option.title = sourceOptions[selectedIds[i]].title;

            // replace the target value if its the last one
            if (targetOptions.length == 1 && targetOptions[0].text == keepTargetLabel) {
                targetOptions[0] = option;
                targetOptions[0].selected = true;
            } else {
                targetOptions[targetOptions.length] = option;
                targetOptions[targetOptions.length-1].selected = true;
            }
        }
    }

    // notify the Select Elements that their contents have changed
    if (targetSelect["onchange"]) {
        targetSelect.onchange();
    }
    if (sourceSelect["onchange"]) {
        sourceSelect.onchange();
    }

    // remove selected values from the source, starting with the last one selected
    for (var i = selectedIds.length - 1; i > -1; i--) {
        sourceSelect.remove(selectedIds[i]);
    }

    // Workaround here for a bug in IE:
    // If you have a select element with many values, and you've scrolled to
    // the bottom and move an option from the top-most element you can now see,
    // IE would not refresh the select element, leaving a hole in the list.
    // By forcing the select element disabled and back, it seems to refresh the
    // element properly.
    sourceSelect.disabled = true;
    sourceSelect.disabled = false;

    // make sure we don't get an empty list
    if (sourceOptions.length == 0) {
        sourceOptions[0] = new Option (keepSourceLabel, keepSourceLabel);
    }

    // if we moved anything, put the focus on the target list box
    if (selectedIds.length > 0) targetSelect.focus ();

    // invoke if the Slect Element has local function
    if (targetSelect["onLocalMoveOptions"])
        targetSelect.onLocalMoveOptions();
    if (sourceSelect["onLocalMoveOptions"])
        sourceSelect.onLocalMoveOptions();
    if (! seenWarn) {
        DuelingListBoxesElement.removeWarning(warnDivId);
    }
}

/**
 * Used when submitting a dueling list boxes element.
 * Stores all the values into hidden form parameters so we can get them out
 */
DuelingListBoxesElement.saveAllSelected = function(fromSelectArray, toArray, delim, escape, emptyLabel) {
    var i,j,escapedValue;
    // loop through all the select elements
    for (i = 0; i < fromSelectArray.length; i++) {
        toArray[i].value = ''; // clear out the value to start
        // now loop through all the values in the select element
        for (j = 0; j < fromSelectArray[i].length; j++) {
            // copy over the value as long as it is not the emptyLabel
            if (!(fromSelectArray[i].length == 1 && fromSelectArray[i].options[0].value == emptyLabel)) {
                var val = fromSelectArray[i].options[j].value.replace(new RegExp(escape+escape,"g"), escape+escape);
                toArray[i].value += val.replace(new RegExp(delim,"g"), escape+delim);
            }

            // add the delimiter (except after the last one)
            if (j + 1 < fromSelectArray[i].length) {
                toArray[i].value += delim;
            }
        }
    }
}

/**
 * JS functionality for the Google Talk sidebar gadget (see SidebarModuleGoogleTalkElement.java)
 * @author byang
 * @since 152
 **/
function GoogleTalk(gadget, resizeBar, gadgetUrl) {
    this.gadget = gadget;
    this.gadgetUrl = gadgetUrl;
    this.resizeBar = resizeBar;
    this.resizeBarOrigHeight = resizeBar.style.height;
    this.mouseStatus = 'up';
    this.popupWindow = function() {};
    this.showOnExitOverlay = true;

    var cookieHeight = getCookie(GoogleTalkConstants.HEIGHT_COOKIE);
    this.expandedHeight = cookieHeight == null || cookieHeight == 0 ?
        GoogleTalkConstants.EXPANDED_HEIGHT : cookieHeight;

    // For some reason, in IE6, if the talk gadget is loaded before bodyOnLoad() is executed,
    // the JS gets crossed-up and nothing works.  So, the loading is deferred until GoogleTalk
    // is registered, which happens in bodyOnLoad() (see SidebarGoogleTalkGadget.java)
    if (this.gadget.height != GoogleTalkConstants.COLLAPSED_HEIGHT) {
        this.gadget.src = this.gadgetUrl;
    }

    /**
     * Shows/hides the gadget.  Also shows/hides the resize bar
     **/
    GoogleTalk.prototype.toggle = function(hiddenLinks, shownLinks) {
        var isExpanding = this.gadget.height == GoogleTalkConstants.COLLAPSED_HEIGHT;

        this.gadget.height = (isExpanding ? this.expandedHeight : GoogleTalkConstants.COLLAPSED_HEIGHT);

        // this is important: by blanking out the source of the iframe, we disconnect from Google Talk
        if (isExpanding) {
            this.gadget.src = this.gadgetUrl;
        } else {
            this.gadget.src = UrlMap.getURL("BlankPage");
        }

        // set a cookie denoting that the user has collapsed or expanded the gadget
        var expires = new Date();
        expires.setTime(expires.getTime() + (3650*24*60*60*1000));
        setCookie(GoogleTalkConstants.COLLAPSED_COOKIE, isExpanding ? '0' : '1', expires);

        // toggle the links that are shown
        if (isExpanding) {
            shownLinks.style.display = 'inline';
            hiddenLinks.style.display = 'none';
        } else {
            shownLinks.style.display = 'none';
            hiddenLinks.style.display = 'inline';
        }

        // hide the resize bar
        this.resizeBar.style.display = isExpanding ? 'block' : 'none';

        // force resize handling in the console
        if (typeof resizeFramesToFit != 'undefined') {
            resizeFramesToFit();
        }
    }

    /**
     * Resizes the gadget while the user is dragging
     **/
    GoogleTalk.prototype.resize = function(e) {
        if(this.mouseStatus == 'down'){
            var curevent = (typeof event == 'undefined' ? e : event);
            // get new mouse position and calculate movement in pixels
            var newPos = curevent.clientY;
            var newHeight=parseInt(this.curHeight + parseInt(newPos - this.curPos));
            //conditional to set minimum height to 5
            newHeight = ( newHeight < GoogleTalkConstants.MIN_EXPANDED_HEIGHT ? GoogleTalkConstants.MIN_EXPANDED_HEIGHT : newHeight);
            //set the new height of the div
            this.gadget.height = newHeight;
        }
    }

    /**
     * Initiates resizing
     **/
    GoogleTalk.prototype.setStartDrag = function(e) {
        //for handling events in ie vs. w3c
        var curevent = (typeof event == 'undefined' ? e : event);

        // some trickery to allow the user ample space to drag their mouse without killing the drag by mousing over the gadget
        this.resizeBar.style.height = '39px';
        var newHeight = this.gadget.height - 35;
        this.gadget.height = newHeight > GoogleTalkConstants.MIN_EXPANDED_HEIGHT ? newHeight : GoogleTalkConstants.MIN_EXPANDED_HEIGHT ;

        //sets mouse flag as down
        this.mouseStatus = 'down';
        //gets position of click
        this.curPos = curevent.clientY;

        this.curHeight = parseInt(this.gadget.height);

        // make the entire page area register the resize events
        document.body.onmousemove = function(e) { GoogleTalk.prototype.theGadget.resize(e); };
        document.body.onmouseup = function(e) { GoogleTalk.prototype.theGadget.setEndDrag(e); };
    }

    /**
     * Ends resizing
     **/
    GoogleTalk.prototype.setEndDrag = function(e) {
        if(this.mouseStatus == 'down') {
            //sets mouse flag as down
            this.mouseStatus='up';
            this.resizeBar.style.height = this.resizeBarOrigHeight;

            var expires = new Date();
            expires.setTime(expires.getTime() + (3650*24*60*60*1000));
            setCookie(GoogleTalkConstants.HEIGHT_COOKIE, this.gadget.height, expires);

            this.expandedHeight = this.gadget.height;
        }
    }

    GoogleTalk.prototype.popout = function(e) {
        //if (typeof(this.popupWindow.focus) != 'undefined' && !this.popupWindow.closed) {
            //this.popupWindow.focus();
        //} else {
            this.popupWindow = window.open(this.gadgetUrl, 'gTalkPopup', 'toolbar=no,width=300,height=600,resizable=yes,toolbars=no,status=no,scrollbars=yes,menubar=no,directories=yes,location=yes,dependant=no', false, false);
        //}
    }


    // used in bbutils.js
    GoogleTalk.prototype.hide = function() {
        this.gadget.height = 0;
    }

    GoogleTalk.prototype.show = function() {
        this.gadget.height = this.expandedHeight;
    }

    GoogleTalk.prototype.isShown = function() {
        return this.gadget.height != GoogleTalkConstants.COLLAPSED_HEIGHT;
    }
}

/**
 * @author zzhou
 * since 148
 * CrtLayout javascript code; also see AvailableSection.js, AvailableField.js, Lookups.js
 */

     CrtLayoutElement.layoutSections = {};
     CrtLayoutElement.layoutSecPos = [];
     MoveableItem.selectedBucket = [];
     LayoutSection.currentSelectedObj = null;
     MoveableItem.currentSelectedObj = null;
     CrtLayoutElement.mouseDown = false;
     CrtLayoutElement.dragMove = false;
     CrtLayoutElement.CSS_CLASS_SELECTED_SECTION = 'sectionSelected';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION = 'layoutSecHeaderLeft';
     CrtLayoutElement.CSS_CLASS_SELECTED_ITEM = 'itemSelected';
     CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR_HIGHLIGHT = 'sepCellHighlight';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR_HIGHLIGHT = 'sepSectionHighlight';
     CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR = 'sepSection';
     LayoutItemSeparator.highlightSep = null;
     LayoutSection.NEW_SECTION_ID_PREFIX = "newSectionId";
     LayoutSection.NEW_SECTION_SEP_ID_PREFIX = "newSectionSepId";
     LayoutSection.sectionIdInterator = 0;
     CrtLayoutElement.FIELD_SEP = '$';
     CrtLayoutElement.COL_SEP = '|';
     CrtLayoutElement.DIV_SEP = '_';
     CrtLayoutElement.sectionNameIdMap = {};
     CrtLayoutElement.initialStateColIdMap = null;
     CrtLayoutElement.lookupItemPosMap = {};
     CrtLayoutElement.currentDisplayedSec = null;
     CrtLayoutElement.NUM_ROWS_PER_AVAILABLE_SECTION = 8;
     CrtLayoutElement.disableButtons = false;
     CrtLayoutElement.HOVER_TIME_OUT = 1000;
     CrtLayoutElement.availableSectionPosInited = false;
     CrtLayoutElement.availableSectionInitPosY = 0;
     CrtLayoutElement.sectionsToReformat = {};

     LayoutItem.prototype.createNewCellId = function() {
        return this.sectionId + 'r'+this.rowPos+'c'+(this.colPos+1);
     }

     LayoutItemSeparator.prototype.createNewCellId = function() {
        return 'rp_'+this.sectionId + 'r'+this.rowPos+'c'+(this.colPos+1);
     }

     CrtLayoutElement.init = function() {
         document.onmousemove = function(evt) {CrtLayoutElement.handleMouseMove(evt)};
         document.onmouseup = function(evt) {CrtLayoutElement.handleMouseUp(evt)};
         window.onscroll = function(evt) {CrtLayoutElement.scrollAvailableSection(evt)};
         sfdcPage.appendToOnloadQueue(CrtLayoutElement.onLoad,"onLoad Scripts for the CrtLayout Page");
     }

     CrtLayoutElement.onLoad = function() {
        setTimeout('CrtLayoutElement.initLoad()',10);
     }

     CrtLayoutElement.handleMouseOver = function() {

     }

    CrtLayoutElement.openPropertiesEdit = function(evt) {
        if (!MoveableItem.currentSelectedObj) {
            alert(LC.getLabel("CrtLayout","mustSelectField"));
            return;
        }
        if (MoveableItem.currentSelectedObj.isSection) {
            CrtLayoutElement.openSectionPopup(evt,MoveableItem.currentSelectedObj.fieldObj.sectionId);
            return;
        }

        evt = getEvent(evt);
        setLastMousePosition(evt);


        var url = MoveableItem.currentSelectedObj.inLayout ? CrtLayoutElement.CRT_FIELD_EDIT_URL : "";
        var h = (MoveableItem.selectedBucket.length > 2) ? 400 : 200;
        openPopup(url, 'sectionEdit', 450, h, 'width=450,height='+h+',scrollbars=yes,toolbar=no,status=no,directories=no,menubar=no,resizable=yes', true);
        return false;

    }

     CrtLayoutElement.swapAvailableType = function(sel,fromPageNum,toPageNum) {
        if (CrtLayoutElement.currentDisplayedSec) {
            CrtLayoutElement.currentDisplayedSec.swapFromPage(fromPageNum);
        }
        var secId = sel.options[sel.selectedIndex].value;
        CrtLayoutElement.availableSections[secId].swapToPage(toPageNum);
     }

    CrtLayoutElement.getPrimObjMetaMap = function() {
        return CrtLookups.primaryObjects;
    }

    CrtLayoutElement.getLookupIdFromPrimObjId = function(primaryObjId) {
        return primaryObjId+'_'+LookupsUi.LOOKUPS;
    }

    CrtLayoutElement.setLookupItemPostion = function(fieldValue, fieldObj) {
        if (CrtLayoutElement.lookupItemPosMap == null) {
            CrtLayoutElement.lookupItemPosMap = {};
        }
        CrtLayoutElement.lookupItemPosMap[fieldValue] = fieldObj;
    }

    CrtLayoutElement.clearTextSelection = function(){
        if (isIE) {
            document.selection.empty();
        } else {
          if (window.getSelection().removeAllRanges) {
              window.getSelection().removeAllRanges();
          }
        }
    }

    CrtLayoutElement.deleteSection = function(sectionId) {
        var section = CrtLayoutElement.layoutSections[sectionId];
        if (!section.isEmpty && !window.confirm(LC.getLabel("LayoutDND", "confirmDeleteSectionPrompt") + '\n\n' + LC.getLabel("Global", "are_you_sure"))) {
            return;
        }

        section.remove();

        CrtLayoutElement.layoutSections[sectionId].numFields = 0;
        CrtLayoutElement.checkDisableSave();
        //delete
        delete CrtLayoutElement.layoutSections[sectionId];
        //this name no longer exists for lookup fields
        delete CrtLayoutElement.sectionNameIdMap[section.labelName];

    }

    CrtLayoutElement.createNewSection = function(sectionName, evt) {
        if (sectionName) {
            var sec = initSectionTable(null,null, null, 'H', sectionName);
            sec.reformatSection();
            sec.attachItemEvents();
            return sec;
        }
    }

    CrtLayoutElement.openSectionPopup = function(evt,sectionId) {
        var url = CrtLayoutElement.CRT_SECTION_EDIT_URL;
        if (sectionId) {
          url += '?sectionId=' + sectionId;
        }
        evt = getEvent(evt);
        setLastMousePosition(evt);
        openPopup(url, 'sectionEdit', 450, 245, 'width=450,height=245,scrollbars=yes,toolbar=no,status=no,directories=no,menubar=no,resizable=yes', true);
    }

    CrtLayoutElement.handleMouseUp = function(evt) {
        if (CrtLayoutElement.dragMove) {
            document.getElementById('dragDummy').style.visibility = 'hidden';
             //Shouldn't be handling mouseup here but on the element itself but that seems broken (broken on FIREFOX) - for now...so handle it here
            CrtLayoutElement.handleSelectedItems();
            MoveableItem.clearSelectedItems();
            CrtLayoutElement.clearHighlights();
            CrtLayoutElement.dragMove = false;
        }
        CrtLayoutElement.mouseDown = false;
     }

     CrtLayoutElement.clearHighlights = function() {
        if (CrtLayoutElement.highlightAvailSection) {
            CrtLayoutElement.highlightAvailSection.handleMouseUp(null);

        }
        if (CrtLayoutElement.highlightSec) {
            CrtLayoutElement.highlightSec.setHighlighted(false);
        }
        if (LayoutItemSeparator.highlightSep) {
            LayoutItemSeparator.highlightSep.setHighlighted(false);
        }
     }

     CrtLayoutElement.handleMouseMove = function(evt) {
        var evt = getEvent(evt);
        if (MoveableItem.currentSelectedObj && CrtLayoutElement.mouseDown) {
            CrtLayoutElement.dragMove = true;
            CrtLayoutElement.clearTextSelection();
            var scrollX = getScrollX();
            var scrollY = getScrollY();
            var dragDummy = document.getElementById('dragDummy');
            var dragDummyValue = document.getElementById('dragDummyValue');
            dragDummy.style.visibility = 'visible';
            if (MoveableItem.currentSelectedObj.isSection) {
                dragDummyValue.innerHTML =  MoveableItem.selectedBucket.length > 1 ? LC.getLabel("CrtLayout","dragMultiSelect") : MoveableItem.currentSelectedObj.fieldName;
            } else {
                dragDummyValue.innerHTML = MoveableItem.selectedBucket.length > 1 ? LC.getLabel("CrtLayout","dragMultiSelect") : MoveableItem.currentSelectedObj.fieldName;
            }

            var parentX = 0;
            var parentY = 0;
            if (dragDummy.offsetParent) {
               var dummyParent = dragDummy.offsetParent;
               parentX = getObjX(dummyParent);
               parentY = getObjY(dummyParent);
            }
            dragDummy.style.left = (getMouseX(evt) - parentX) + "px";
            dragDummy.style.top = (getMouseY(evt) - parentY) + "px";
            var currentX = getObjX(dragDummy) - scrollX;
            var theWidth = 500;
            if (document.documentElement && document.documentElement.clientWidth)
                theWidth = document.documentElement.clientWidth;
            else if (document.body) {
                theWidth = document.body.clientWidth;
                if (currentX > theWidth) {
                    if (isIE) document.body.scrollLeft = document.body.scrollLeft + 10;
                    //else window.scroll(10, 0);
                } else if (currentX < 0) {
                    if (isIE) document.body.scrollLeft = document.body.scrollLeft - 10;
                    //else window.scroll(-10, 0);
                }
            }
            else {

            }
            var currentY = getObjY(dragDummy) - scrollY;
            var theHeight = 500;
            if (document.documentElement && document.documentElement.clientHeight)
                theHeight = document.documentElement.clientHeight;
            else if (document.body) {}
                theHeight = document.body.clientHeight;
                if (currentY > theHeight - 50) {
                    //if (isIE) document.documentElement.scrollTop = document.body.scrollTop + 50;
                    window.scrollBy(0, 50);
                } else if (currentY < 50) {
                    // if (isIE) document.documentElement.scrollTop = document.body.scrollTop - 50;
                    window.scrollBy(0, -50);
                }
            }
            else {
            }
     }

     function initSectionTable(sectionId,sectionHeaderId, sectionTableId, sortOrder, masterLabel) {
         var section = new LayoutSection(sectionId,sectionHeaderId, sectionTableId, sortOrder,masterLabel);
         CrtLayoutElement.layoutSections[section.sectionId] = section;
         //position map to keep track of the positions of the layout sections
         CrtLayoutElement.layoutSecPos.push(section.sectionId);

        //some section name handling
        //for now handle section names so that we place the lookups in the appropriate buckets
        CrtLayoutElement.sectionNameIdMap[masterLabel] = section;
        return section;
     }

     //init the innerHTML on constructing a new table;
     LayoutSection.prototype.initSectionInnerHtml = function() {
        var secDiv = document.createElement("DIV");
        var innerHTML = '';
        secDiv.id = this.sectionId;
        secDiv.className = "layoutSection";
        innerHTML += '<div class="layoutSecHeader"><table  border="0" cellpadding="0" cellspacing="0"><tr><td class="layoutSecHeaderLeft" ';
        innerHTML += 'id="' + this.sectionHeaderId  +'">' + this.labelName + '</td><td class="layoutSecHeaderLink">';
        innerHTML += '<span class="sectionHeadLink" onclick="CrtLayoutElement.openSectionPopup(event,\'' + this.sectionId + '\');">'+LC.getLabel("CrtLayout","sectionEdit")+'</span>';
        innerHTML += '&nbsp;|&nbsp;<span class="sectionHeadLink" onclick="CrtLayoutElement.deleteSection(\'' + this.sectionId + '\');">'+LC.getLabel("CrtLayout","sectionDelete")+'</span></td></table></div>';
        innerHTML += '<div><table id="' + this.sectionTableId + '"class="layoutSectionTable">';
        innerHTML += '</table></div>';
        secDiv.innerHTML = innerHTML;
        return secDiv;
     }

     //init the innerHTML for a new table separator
     LayoutSection.prototype.initSectionSepInnerHtml = function() {
        var sepDiv = document.createElement("DIV");
        sepDiv.id = this.getSectionSepId();
        sepDiv.className = "sepSection";
        return sepDiv;
     }

     LayoutSection.prototype.createSectionId = function() {
        return LayoutSection.NEW_SECTION_ID_PREFIX + '_' + LayoutSection.sectionIdInterator++;
     }

     LayoutSection.prototype.getSectionTableId = function() {
        return this.sectionId + "_layoutItemSection";
     }

     LayoutSection.prototype.getSectionHeaderId = function() {
         return "sec_" + this.sectionId;
     }

     LayoutSection.prototype.getLastSectionSepId = function() {
        return CrtLayoutElement.SECTION_SEP_DIV_PREFIX +CrtLayoutElement.LAST_SEC_SEP_DIV;
     }


     function LayoutSection(sectionId,sectionHeaderId, sectionTableId, sortOrder, masterLabel) {
         this.labelName = masterLabel;
         if (sectionId == null) {
             this.sectionId = this.createSectionId();
             this.sectionHeaderId = this.getSectionHeaderId();
             this.sectionTableId = this.getSectionTableId();
             var parentNode = document.getElementById("mainTableDiv");
             var lastSecSep = document.getElementById(this.getLastSectionSepId());
             var sepDiv = this.initSectionSepInnerHtml();
             parentNode.insertBefore(sepDiv,lastSecSep);
             parentNode.insertBefore(this.initSectionInnerHtml(),lastSecSep);
             new LayoutSectionSeparator(sepDiv.id, this.sectionId);
             this.sectionValue = "";
             this.attachEvents();
         } else {
             this.sectionId = sectionId;
             this.sectionHeaderId = sectionHeaderId;
             this.sectionTableId = sectionTableId;
             this.sectionValue = sectionId;
         }

         this.sortOrder = sortOrder;
         this.isSelected = false;
         this.numCols = CrtLayoutElement.NUM_LAYOUT_COLS;
         this.numRows = 0;
         this.layoutItems = [];
         //only here to keep the separator objects alive
         this.layoutSeparators = [];
         this.fieldsMap = {};
         this.isEmpty = true;
     }

    //move cell -- or more precisely move contents of fromField to the contents of toField
    LayoutSection.prototype.moveCell = function(toField,fromField) {
            toField.sectionId = this.sectionId;
            toField.customName = fromField.customName;
            toField.displayName = fromField.displayName;
            toField.fieldName = fromField.fieldName;
            toField.fieldId = fromField.fieldId;
            toField.isEmpty = fromField.isEmpty;
            toField.type = fromField.type;
            toField.isLookup = fromField.isLookup;
            toField.defaultChecked = fromField.defaultChecked;
            fromField.isEmpty = true;
    }

    LayoutSection.prototype.insertCell = function(toField,moveableItem) {
        toField.fieldName = moveableItem.fieldName;
        toField.displayName = moveableItem.displayName;
        toField.customName = moveableItem.customName;
        toField.type = moveableItem.type;
        toField.fieldId = moveableItem.itemId;
        toField.isLookup = moveableItem.isLookup;
        toField.defaultChecked = moveableItem.defaultChecked;
        toField.isEmpty = false;
    }

    LayoutItem.prototype.setCellToEmpty = function() {
        this.itemElem.innerHTML = '';
    }


     //insert a table row in the html for this layout section
     //update internal object references
     LayoutSection.prototype.insertSectionRow = function() {
        var tableElem = document.getElementById(this.sectionTableId);
        var row = tableElem.insertRow(-1);
        var numRows = this.numRows;
        for (var i=0; i<this.numCols; i++) {
            setSeparatorAttributes(this.sectionId,null,numRows,i,row);
            setEmptyFieldAttributes(this.sectionId,null,numRows,i,row);
        }
     }

    //delete an extra empty row in a section
    LayoutSection.prototype.deleteSectionRow = function() {
        var tableElem = document.getElementById(this.sectionTableId);
        tableElem.deleteRow(-1);
        this.layoutItems.splice(this.numRows-1,1);
        this.layoutSeparators.splice(this.numRows-1,1);
        this.numRows--;
    }

    //reformat section after putting in cells from selected bucket
    //alignment is from left to right; cells automatically align as far left on their row as possible
    //@ param isLoad specifies whether we are calling this on loading the page or not -- if we are loading, we don't do most of the formatting for speed
    LayoutSection.prototype.reformatSection = function(isLoad) {
        var columnSize = this.numCols;
        var pos =0;
        var lastEmpty= -1; //assume non cells Empty at start
        var row, col;
        for (var lastEmpty = -1, pos = 0; Math.floor(pos / columnSize) < this.numRows; pos++) {
            row = Math.floor(pos / columnSize);
            col = (pos % columnSize);
            //if we see a nonEmptyCell, copy it over
            if (!this.layoutItems[row][col].isEmpty) {
                 if (lastEmpty == -1) {
                     continue;
                 }
                 this.moveCell(this.layoutItems[Math.floor(lastEmpty/columnSize)][lastEmpty%columnSize],
                             this.layoutItems[row][col]);

                 //move lastEmptyPosition
                 lastEmpty++;
            }
            else {
                if (lastEmpty == -1) {
                    lastEmpty = pos;
                }
            }
        }

        var lastNonEmpty = lastEmpty-1;
        this.isEmpty = true;

        if (lastEmpty >= 0 && (pos-columnSize) > lastNonEmpty) {
            var emptyRows = Math.floor((pos-1-lastNonEmpty)/columnSize);
            //if we have more than one empty row, delete the extras
            while (emptyRows > 1) {
               this.deleteSectionRow();
               emptyRows--;
            }
        }
        else {
            //else we have no empty rows, so add one here
            this.insertSectionRow();
        }
        this.numFields = 0;

        //set cell style
        for (var j = 0; j < this.numRows; j++) {
            for (var k = 0; k < this.numCols; k++) {
                var field = this.layoutItems[j][k];
                this.fieldsMap[field.itemId] = field;
                var sep = this.layoutSeparators[j][k];
                if (!isLoad) {
                    sep.setHighlighted(false);
                }
                if (!isLoad || field.isEmpty) {
                    field.formatField();
                }
                if (!field.isEmpty) {
                    this.isEmpty = false;
                    this.numFields++;
                    //set lookup positioning
                    if (field.isLookup) {
                        CrtLayoutElement.setLookupItemPostion(field.fieldId,field);
                    }
                }

            }
        }

        //attach the the event handlers that would handle the events on the LayoutItems
        if (isLoad) {
            this.attachItemEvents();
        }
    }

    //theorically it will make more sense to attach event handlers to the individual field element themselves
    //however setting all the event handlers on each of the fields would take too long on a page with many fields
    //thus we attach events to the parent element and then delegate to the appropriate event handler during events
    LayoutSection.prototype.attachItemEvents = function() {
         var self = this;
         var tableElem = document.getElementById(self.sectionTableId);
         addEvent(tableElem, 'click', function(evt) {self.handleItemMouseClick(evt);}, false);
         addEvent(tableElem, 'mousedown', function(evt) {self.handleItemMouseDown(evt);}, false);
         addEvent(tableElem, 'mouseover', function(evt) {self.handleItemMouseOver(evt);}, false);
         addEvent(tableElem, 'dblclick', function(evt) {self.handleItemMouseDblClick(evt);}, false);
         addEvent(tableElem, 'mouseout', function(evt) {self.handleItemMouseOut(evt);}, false);
    }

    LayoutSection.prototype.handleItemMouseClick = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseClick(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseDown = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseDown(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseOver = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseOver(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseDblClick = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseDblClick(evt);
        }
    }

    LayoutSection.prototype.handleItemMouseOut = function(evt) {
        var elem = getEventTarget(evt);
        var field = this.fieldsMap[elem.id];
        if (field) {
            if (!field.elem) {
                field.itemElem = elem;
            }
            field.handleMouseOut(evt);
        }
    }

    CrtLayoutElement.disableLayoutButtons = function(disableButton) {
        if (disableButton) {
            //if there are empty sections, disable both save and preview layout buttons
            for (var i=0; i<2; i++) {
                if (document.getElementsByName("saveAndCloseButton")[i]) {
                    document.getElementsByName("saveAndCloseButton")[i].className = 'btnDisabled';
                    document.getElementsByName("saveAndCloseButton")[i].disabled = true;
                    document.getElementsByName("previewButton")[i].className = 'btnDisabled';
                    document.getElementsByName("previewButton")[i].disabled = true;
                    CrtLayoutElement.disableButtons = true;
                }
            }
        }
        else {
        //else, enable buttons
           for (var i=0; i<2; i++) {
              if (document.getElementsByName("saveAndCloseButton")[i]) {
                  document.getElementsByName("saveAndCloseButton")[i].className = 'btn';
                  document.getElementsByName("saveAndCloseButton")[i].disabled = false;
                  document.getElementsByName("previewButton")[i].className = 'btn';
                  document.getElementsByName("previewButton")[i].disabled = false;
                  CrtLayoutElement.disableButtons = false;
              }
          }
        }
    }

    LayoutItem.prototype.handleMoved = function() {
        this.isEmpty = true;
        //reformat any sections as needed
        CrtLayoutElement.sectionsToReformat[this.sectionId] = CrtLayoutElement.getLayoutSection(this.sectionId);
    }

    /*move the cells around the layout
     *param rowPos, colPos specifies position to move these cells to
     */
     LayoutSection.prototype.moveCells = function(rowPos, colPos) {
         //first set the old positions to empty for all the cells being moved
         for (var i=0; i < MoveableItem.selectedBucket.length; i++) {
              MoveableItem.selectedBucket[i].fieldObj.handleMoved();
         }

        var shiftSize = MoveableItem.selectedBucket.length;
        var columnSize = this.numCols;
        //leftmost cell that needs to be moved
        var start = rowPos * columnSize + colPos;

        //rightmost element
        var lastElement = this.numRows * columnSize - 1;
        var lastNonEmptyPos = lastElement;
        if (!this.isEmpty) {
            while (lastNonEmptyPos >= 0 && this.layoutItems[Math.floor(lastNonEmptyPos/columnSize)][lastNonEmptyPos%columnSize].isEmpty) {
                lastNonEmptyPos--;
            }
        } else {
            lastNonEmptyPos = -1;
        }

        //farthest element that can be shifted but still be kept on screen
        var end = lastElement - shiftSize;

        //if we are moving to the very end, then we should just move it right after the lastNonEmptyPos if possible
        start = Math.min(start,lastNonEmptyPos+1);

       //if there are elements that we can't keep on the screen, we might have to increase the row size
       if (lastNonEmptyPos > end) {
            var moreRows = Math.ceil((lastNonEmptyPos + shiftSize - lastElement)/columnSize);
            while (moreRows > 0) {
                this.insertSectionRow();
                moreRows--;
            }
       }

       //shift all elements to the right one by one, starting from the rightmost until we reach the leftmost cell to be moved
       while (lastNonEmptyPos >= start) {
               this.moveCell(this.layoutItems[Math.floor((lastNonEmptyPos+shiftSize)/columnSize)][(lastNonEmptyPos+shiftSize)%columnSize],
                          this.layoutItems[Math.floor(lastNonEmptyPos/columnSize)][lastNonEmptyPos%columnSize]);
              lastNonEmptyPos--;
       }

       //now move all selected cells into vacated spot
       //starting from leftmost moving right
       for (var i =0 ; i < MoveableItem.selectedBucket.length; i++) {
              var selItem = MoveableItem.selectedBucket[i];
              this.insertCell(this.layoutItems[Math.floor((start+i)/columnSize)][(start+i)%columnSize],
                        selItem);
       }
        CrtLayoutElement.sectionsToReformat[this.sectionId] = this;
        CrtLayoutElement.reformatSections();
    }

    CrtLayoutElement.reformatSections = function() {
        for (var sId in CrtLayoutElement.sectionsToReformat) {
            CrtLayoutElement.sectionsToReformat[sId].reformatSection();
        }
        CrtLayoutElement.sectionsToReformat = {};

        CrtLayoutElement.checkDisableSave();

    }

    CrtLayoutElement.checkDisableSave = function() {

        var totalFields = 0;
        for (var sId in CrtLayoutElement.layoutSections) {
            totalFields += CrtLayoutElement.layoutSections[sId].numFields;
        }

        //check for fields limits
        var counter = document.getElementById('fieldsCounterInner');
        var counter2 = document.getElementById('fieldsCounterInner2');
        counter.innerHTML = totalFields;
        counter2.innerHTML = totalFields;
        if (totalFields > CrtLayoutElement.LAYOUT_FIELDS_LIMIT) {
            counter.style.color = '#CC0000';
            counter2.style.color = '#CC0000';
            if (document.getElementById('fieldsLimitError').style.display == 'none') {
                alert(LC.getLabel("CrtLayout","fieldsLimitErrorMsg",CrtLayoutElement.LAYOUT_FIELDS_LIMIT));

                //there's something weird with the order these statements are being run -- hide the dragDummy again because this alert clears the execution of the prior hiding of this dragDummy
                document.getElementById('dragDummy').style.visibility = 'hidden';
            }
            document.getElementById('fieldsLimitError').style.display = 'block';
            document.getElementById('fieldsLimitError2').style.display = 'block';
            CrtLayoutElement.disableLayoutButtons(true);
        } else {
            counter.style.color = 'green';
            counter2.style.color = 'green';
            document.getElementById('fieldsLimitError').style.display = 'none';
            document.getElementById('fieldsLimitError2').style.display = 'none';

            //if all fields are empty then we also disable the layout buttons
            if (totalFields > 0) {
                CrtLayoutElement.disableLayoutButtons(false);
            } else {
                CrtLayoutElement.disableLayoutButtons(true);
            }
        }
    }

    CrtLayoutElement.handleSelectedItems = function() {
        if (CrtLayoutElement.highlightSec) {
            CrtLayoutElement.moveSections();
        }
        else if (CrtLayoutElement.highlightAvailSection) {
            CrtLayoutElement.highlightAvailSection.moveCells();
        }
        else if (LayoutItemSeparator.highlightSep) {
            var itemSep = LayoutItemSeparator.highlightSep;
            CrtLayoutElement.getLayoutSection(itemSep.sectionId).moveCells(itemSep.rowPos, itemSep.colPos);
        } else {
        }
   }

   //move layout sections around in drag and drop
   CrtLayoutElement.moveSections = function() {
        //find the highlighted sec separator and insert all selected sections after this separator
        //find the of the section position we are inserting before
        var moveSecPos;
        var highlightSec = CrtLayoutElement.highlightSec;

        var moveToSep = document.getElementById(highlightSec.divId);
        var parentNode = document.getElementById(highlightSec.divId).parentNode;
        for (var i=0; i < MoveableItem.selectedBucket.length; i++) {
            if (MoveableItem.selectedBucket[i].isSection) {
                var sectionObj = MoveableItem.selectedBucket[i].fieldObj;
                var secDiv = document.getElementById(sectionObj.sectionId);
                var sepDivId = sectionObj.getSectionSepId();
                var sepDiv = document.getElementById(sepDivId);
                //insert both the section Div and the sep div that separates it from the next section
                parentNode.insertBefore(sepDiv,moveToSep);
                parentNode.insertBefore(secDiv,moveToSep);

                //remove the section
                for (var k=0; k<CrtLayoutElement.layoutSecPos.length;k++) {
                    if (sectionObj.sectionId == CrtLayoutElement.layoutSecPos[k]) {
                        CrtLayoutElement.layoutSecPos.splice(k,1);
                        break;
                    }
                }
            }
        }

        if (highlightSec.sectionId != CrtLayoutElement.LAST_SEC_SEP_DIV) {
            for (moveSecPos=0; moveSecPos<CrtLayoutElement.layoutSecPos.length; moveSecPos++) {
                if (highlightSec.sectionId == CrtLayoutElement.layoutSecPos[moveSecPos]) {
                    break;
                }
            }
        } else {
            //if we are inserting before the last section separator, we are inserting at the end
            moveSecPos = -1;
        }

        //insert the section into its new position
        for (var l=0; l<MoveableItem.selectedBucket.length; l++) {
            if (MoveableItem.selectedBucket[l].isSection) {
                //insert at the end
                if (moveSecPos < 0) {
                   CrtLayoutElement.layoutSecPos.push(MoveableItem.selectedBucket[l].fieldObj.sectionId);
                } else {
                   CrtLayoutElement.layoutSecPos.splice(moveSecPos,0,MoveableItem.selectedBucket[l].fieldObj.sectionId);
                }
            }
        }

   }


    LayoutSection.prototype.getSectionSepId = function() {
        return CrtLayoutElement.SECTION_SEP_DIV_PREFIX + this.sectionId;
    }


     LayoutSection.prototype.insertSepItemRow = function(itemObj){
        this.layoutSeparators[itemObj.rowPos] = [];
        if (itemObj.rowPos == this.numRows) {
            this.numRows++;
        }
     }

     LayoutSection.prototype.insertSeparatorCell = function(itemObj) {
         if (!this.layoutSeparators[itemObj.rowPos]) {
             this.insertSepItemRow(itemObj);
         }
         this.layoutSeparators[itemObj.rowPos][itemObj.colPos] = itemObj;
     }

     LayoutSection.prototype.insertItemRow = function(itemObj){
        this.layoutItems[itemObj.rowPos] = [];
        if (itemObj.rowPos == this.numRows) {
            this.numRows++;
        }
     }

     LayoutSection.prototype.insertField = function(itemObj) {
         if (!this.layoutItems[itemObj.rowPos]) {
             this.insertItemRow(itemObj);
         }
         this.layoutItems[itemObj.rowPos][itemObj.colPos] = itemObj;
     }

     LayoutSection.prototype.attachEvents = function() {
         var self = this;
         var tableElem = document.getElementById(self.sectionHeaderId);
         addEvent(tableElem, 'click', function(evt) {self.handleMouseClick(evt);}, false);
         addEvent(tableElem, 'mousedown', function(evt) {self.handleMouseDown(evt);}, false);
         addEvent(tableElem, 'mouseover', function(evt) {self.handleMouseOver(evt);}, false);
         addEvent(tableElem, 'dblclick', function(evt) {self.handleMouseDblClick(evt);}, false);
         addEvent(tableElem, 'mouseout', function(evt) {self.handleMouseOut(evt);}, false);
     }

     LayoutSection.prototype.handleMouseClick = function(evt) {
        var evt= getEvent(evt);
        if (evt.ctrlKey) {
            this.toggleSelected(true);
        } else {

        }
     }

     LayoutSection.prototype.handleMouseDblClick = function(evt) {
         CrtLayoutElement.openPropertiesEdit(evt);
     }

    LayoutSection.getSection = function(rowNum,colNum) {
        return LayoutSection.sections[rowNum][colNum];
    }

     LayoutSection.prototype.handleMouseUp = function(evt) {


     }

     LayoutSection.prototype.handleMouseDown = function(evt) {
       var evt = getEvent(evt);
       if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
            this.toggleSelected(false);
       }
       CrtLayoutElement.mouseDown = true;
    }

    LayoutSection.prototype.handleMouseOut = function(evt) {
        document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
        clearTimeout(this.timeOut);
        this.mousingOver = false;
    }


    LayoutSection.prototype.handleMouseOver = function(evt) {
        var evt = getEvent(evt);
        this.posX = getMouseX(evt);
        this.posY = getMouseY(evt);
        if (!CrtLayoutElement.dragMove && !this.mousingOver) {
            var self = this;
            this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
            this.mousingOver = true;
        }

    }

    LayoutSection.prototype.setupMouseOverDiv = function(evt) {
        var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
        var html = '';
        var posx = this.posX+10;
        var posy = this.posY-60;
        html += '<div class="mouseOverHeader">'+ this.labelName + '</div>';
        html += '<div class="mouseOverBody">' + LC.getLabel("CrtLayout","layoutSecHover");
        html += '</div>';
        moElem.innerHTML = html;

        moElem.style.left = posx+"px";
        moElem.style.top = posy+"px";
        moElem.style.display = 'block';
        return moElem;
    }

LayoutSection.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
}

LayoutSection.prototype.createMoveableItem = function() {
    return new MoveableItem(this.sectionId, this.labelName, this.labelName, this.labelName, 'SECTION', this, true, true, false, false);
}

LayoutSection.prototype.removeSelection = function(noBucketRemove) {
    if (!noBucketRemove && this.moveableItem) {
        this.moveableItem.removeSelection();
    }
    this.moveableItem = null;
    this.removeSelectionFormatting();
}

LayoutSection.prototype.remove = function() {
    this.removeSelection();

    for (var j = 0; j < this.numRows; j++) {
        for (var k = 0; k < this.numCols; k++) {
            var field = this.layoutItems[j][k];
                if (!field.isEmpty) {
                    field.addSelection();
                }
        }
    }

    //move all the fields back
    if (CrtLayoutElement.currentDisplayedSec) {
        CrtLayoutElement.currentDisplayedSec.moveCells();
    }

    MoveableItem.clearSelectedItems();
    this.isEmpty = true;

    //reorder sections
    for (var i=0; i<CrtLayoutElement.layoutSecPos.length;i++) {
        if (this.sectionId == CrtLayoutElement.layoutSecPos[i]) {
            CrtLayoutElement.layoutSecPos.splice(i,1);
            break;
        }
    }

    //remove the element
    var parentNode = document.getElementById(this.sectionId).parentNode;
    parentNode.removeChild(document.getElementById(this.sectionId));
    //remove the section separator
    parentNode.removeChild(document.getElementById(this.getSectionSepId()));

}


LayoutSection.prototype.addSelection = function() {
    var addSelection;
    this.moveableItem = this.createMoveableItem();
    addSelection = this.moveableItem.addSelection();
    //are we mixing the selection Bucket?
    if (addSelection) {
        this.addSelectionFormatting();
    }
}

LayoutSection.prototype.removeSelectionFormatting = function() {
    this.isSelected = false;
    this.render();

}

LayoutSection.prototype.addSelectionFormatting = function() {
    this.isSelected = true;
    this.render();
}

LayoutSection.prototype.render = function() {
    var headerElem = document.getElementById(this.sectionHeaderId);
    headerElem.innerHTML = this.labelName;
    headerElem.className = CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION;
    if (this.isSelected) {
        headerElem.className += ' '+CrtLayoutElement.CSS_CLASS_SELECTED_SECTION;
    }
}



     function setFieldAttributes(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, defaultChecked) {
        var item = new LayoutItem(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, false, null, defaultChecked);
        item.insertField();
     }

     function setEmptyFieldAttributes(sectionId,elementId,rowPos,colPos,rowObj) {
        new LayoutItem(sectionId,elementId,null,null,null,null,null,rowPos,colPos,true,false, true, rowObj,false).insertField();
     }


    function LayoutItem(sectionId, elementId, fieldId, fieldName, displayName, customName, type, rowPos, colPos, inLayout, isLookup, isEmpty, rowObj, defaultChecked) {
         this.sectionId = sectionId;
         this.rowPos = rowPos;
         this.colPos = colPos;
         if (elementId == null && fieldId == null) {
             this.itemElem  = rowObj.insertCell(rowObj.cells.length);
             this.itemId = this.createNewCellId();
             this.itemElem.id = this.itemId;
         }
         else {
             this.itemId = elementId;
         }

         this.isEmpty = isEmpty;
         this.fieldId = fieldId;
         this.customName = customName;
         this.fieldName = escapeHTML(fieldName);

         this.isSelected = false;

         this.type = type;
         this.inLayout = inLayout;
         this.isLookup = isLookup;
         this.defaultChecked = defaultChecked;

         //this takes too long to set for lookup fields -- set it when we actually hover
         this.displayName = this.isLookup ? null : displayName;
    }


    LayoutItem.prototype.setupMouseOverDiv = function(evt) {
        var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
        var html = '';
        var posx = this.posX+10;
        var posy = this.posY-60;
        html += '<div class="mouseOverHeader">'+ this.fieldName + (this.isLookup ? ' ' + LC.getLabel("CRTLookupLayer","viaLookupParen") : '') + '</div>';
        if (!this.displayName) {
            this.displayName = CrtLayoutElement.getDisplayPath(this.fieldId,true);
        }
        html += '<div class="mouseOverBody">' + LC.getLabel("CrtLayout","CustomLabel") + ': '+ (this.customName ? this.customName : this.displayName) + '<br>';
        html += LC.getLabel("CrtLayout","defaultState") +' ';
        if (this.defaultChecked) {
              html += LC.getLabel("CrtLayout","checked");
        } else {
            html += LC.getLabel("CrtLayout","unchecked");
        }
        html += ' <br> ';
        html += LC.getLabel("CrtLayout","sourceObject") + ' ';
        //get source object
        var primObjId = this.isLookup ? CrtLayoutElement.getPrimObjId(this.fieldId,'.') : CrtLayoutElement.getPrimObjId(this.fieldId,CrtLayoutElement.FIELD_SEP);
        var sourceObject = CrtLayoutElement.getPrimObjMetaMap()[primObjId].label;
        if (this.isLookup) {
            html += CrtLayoutElement.getLookupFieldFromPath(CrtLayoutElement.getPath(this.fieldId)).lookupLabel + '<br>(' +LC.getLabel("CrtLayout","associatedWith")+' ' + sourceObject +')';
        } else {
            html += sourceObject;
        }
        html += '<br>';
        if (this.isLookup) {
            html += '<br>';
            html += LC.getLabel("CrtLayout","lookupPath") + ' ' + CrtLayoutElement.getDisplayPath(this.fieldId,false);
            html += '<br>';
        }
        moElem.innerHTML = html;

        moElem.style.left = posx+"px";
        moElem.style.top = posy+"px";
        moElem.style.display = 'block';
        return moElem;
    }

    function MoveableItem(itemId, fieldName, displayName, customName, type, fieldObj, inLayout, isSection, isLookup, defaultChecked) {
        this.itemId = itemId;
        this.fieldName = fieldName;
        this.displayName = displayName;
        this.customName = customName;
        this.type = type;
        this.fieldObj = fieldObj;
        this.inLayout = inLayout;
        this.isSection = isSection;
        this.isLookup = isLookup;
        this.defaultChecked = defaultChecked;
    }

    //insert a field into the Layout Section Object
    LayoutItem.prototype.insertField = function() {
        CrtLayoutElement.layoutSections[this.sectionId].insertField(this);
    }

    //format a field - set background color
    LayoutItem.prototype.formatField = function() {
        if (!this.itemElem) {
            this.itemElem = document.getElementById(this.itemId);
        }
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_CELL;
        if (!this.isEmpty) {
             className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM;
             if (this.isSelected) {
                className += ' ' + CrtLayoutElement.CSS_CLASS_SELECTED_ITEM;
             }
             var innerHTML = '';
             var formattedName = this.formatName(this.fieldName);
             if (this.defaultChecked) {
                 innerHTML += CrtLayoutElement.DFLT_CHECKED_ICON_URL;
             }
             if (this.isLookup) {
                innerHTML += CrtLayoutElement.LOOKUP_ICON_URL;
            }
            if (innerHTML != '') {
                innerHTML += ('&nbsp;' + formattedName);
            } else {
                innerHTML = formattedName;
            }
            this.itemElem.innerHTML = innerHTML;
        } else {
            this.setCellToEmpty();
        }
        this.itemElem.className = className;
    }

    LayoutItem.prototype.formatName = function(fieldName) {
        if (!fieldName) {
            return '';
        }
        //truncate more characters if we have the other icons on the tiles also
        var maxLength = CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH - (this.defaultChecked ? 3 : 0) - (this.isLookup ? 2 : 0);

        if (fieldName.length > maxLength) {
            return fieldName.substring(0,maxLength-2)+"...";
        }
        else {
            return fieldName;
        }
    }

    LayoutItem.prototype.handleMouseOut = function() {
        if (this.isEmpty) {
            return;
        }
        document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
        clearTimeout(this.timeOut);
        this.mousingOver = false;
    }

    LayoutItem.prototype.handleMouseDown = function(evt) {
       if (this.isEmpty) {
           return;
       }
       var evt = getEvent(evt);
       if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
            this.toggleSelected(false);
       }
       CrtLayoutElement.mouseDown = true;
    }

    LayoutItem.prototype.handleMouseOver = function(evt) {
        var evt = getEvent(evt);
        this.posX = getMouseX(evt);
        this.posY = getMouseY(evt);
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && !MoveableItem.currentSelectedObj.isSection) {
           var sectionObj = CrtLayoutElement.getLayoutSection(this.sectionId);
           CrtLayoutElement.clearHighlights();
           var sepObj = sectionObj.layoutSeparators[this.rowPos][this.colPos];
           sepObj.setHighlighted(true);
        } else {
            if (!this.isEmpty && !CrtLayoutElement.dragMove && !this.mousingOver) {
                 var self = this;
                 this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
                 this.mousingOver = true;
            }
        }
    }

    LayoutSection.prototype.getSepCell = function(rowPos,colPos) {
        return this.layoutSeparators[rowPos][colPos];
    }

    CrtLayoutElement.getLayoutSection = function(sectionId) {
        return CrtLayoutElement.layoutSections[sectionId];
    }

    LayoutItem.prototype.handleMouseDblClick = function(evt) {
        if (this.isEmpty) {
            return;
        }
        CrtLayoutElement.openPropertiesEdit(evt);
    }


    LayoutItem.prototype.handleMouseClick = function(evt) {
        if (this.isEmpty) {
            return;
        }
        var evt = getEvent(evt);
        if (evt.shiftKey && MoveableItem.currentSelectedObj) {
            LayoutItem.multiSelect(this);
        } else if (evt.ctrlKey) {
            this.toggleSelected(true);
        } else {

        }
     }

     LayoutItem.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
     }

    //remove all selected elements
    MoveableItem.clearSelectedItems = function() {
        var selB = MoveableItem.selectedBucket;
        for (var i = 0; i < MoveableItem.selectedBucket.length; i++) {
            MoveableItem.selectedBucket[i].fieldObj.removeSelection(true);
        }
        MoveableItem.selectedBucket = [];
        MoveableItem.currentSelectedObj = null;
    }

    LayoutItem.prototype.removeSelectionFormatting = function() {
        this.isSelected = false;
        this.formatField();
    }

    LayoutItem.prototype.createMoveableItem = function() {
        return new MoveableItem(this.fieldId, this.fieldName, this.displayName, this.customName, this.type, this, true, false, this.isLookup, this.defaultChecked)
    }

    LayoutItem.prototype.removeSelection = function(noBucketRemove) {
        if (!noBucketRemove && this.moveableItem) {
            this.moveableItem.removeSelection();
        }
        this.moveableItem = null;
        this.removeSelectionFormatting();
    }

    LayoutItem.prototype.addSelectionFormatting = function() {
        this.isSelected = true;
        this.formatField();
    }

    LayoutItem.prototype.addSelection = function() {
        var addSelection;
        if (this.isEmpty) {
            return;
        }
        this.moveableItem = this.createMoveableItem();
        addSelection = this.moveableItem.addSelection();
        //are we mixing the selection Bucket?
        if (addSelection) {
            this.addSelectionFormatting();
        }
    }

    MoveableItem.prototype.addSelection = function() {
        //make sure we are not mixing sections and items
        if (MoveableItem.currentSelectedObj && (this.isSection != MoveableItem.currentSelectedObj.isSection)) {
            return false;
        }
        if (isIE5) {
            MoveableItem.selectedBucket = MoveableItem.selectedBucket.concat(this);
        } else {
            MoveableItem.selectedBucket.push(this);
        }

        MoveableItem.currentSelectedObj = this;
        return true;
    }

    MoveableItem.prototype.removeSelection = function() {
         for (var i = 0; i < MoveableItem.selectedBucket.length; i++) {
            if (MoveableItem.selectedBucket[i].itemId == this.itemId) {
                MoveableItem.selectedBucket.splice(i, 1);
            }
        }
        if (MoveableItem.currentSelectedObj == this) {
            MoveableItem.currentSelectedObj = null;
            if (MoveableItem.selectedBucket.length > 0) {
                MoveableItem.currentSelectedObj = MoveableItem.selectedBucket[MoveableItem.selectedBucket.length-1];
            }
        }
    }


    //handleMultiSelect with shift key
    LayoutItem.multiSelect = function(itemObj) {
        //if in different sections, return
        if (MoveableItem.currentSelectedObj.fieldObj.sectionId != itemObj.sectionId) {
            return;
        }
        var previousSelectedItem = MoveableItem.currentSelectedObj;
        var rowNum1 = previousSelectedItem.fieldObj.rowPos;
        var rowNum2 = itemObj.rowPos;
        var colNum1 = previousSelectedItem.fieldObj.colPos;
        var colNum2 = itemObj.colPos;
        var startRow = Math.min(rowNum1, rowNum2);
        var endRow =  Math.max(rowNum1, rowNum2);
        var startCol =  Math.min(colNum1, colNum2);
        var endCol =  Math.max(colNum1, colNum2);
        if (startRow == endRow && startCol == endCol) {
            itemObj.removeSelection(false);
            return;
        }
        var moving = MoveableItem.selectedBucket;
        MoveableItem.clearSelectedItems();
        CrtLayoutElement.clearTextSelection();
        for (var i = startRow; i <= endRow; i++ ) {
            for (var j = startCol; j <= endCol; j++) {
                 CrtLayoutElement.layoutSections[itemObj.sectionId].getItem(i,j).addSelection();
            }
        }

        MoveableItem.currentSelectedObj = previousSelectedItem;
    }

   CrtLayoutElement.save = function() {
        var xml = CrtLayoutElement.toXML();
        var submitForm = document.forms[CrtLayoutElement.XML_FORM_NAME];
        submitForm.val.value = xml;
        submitForm.submit();
   }

   CrtLayoutElement.toXML = function() {
        var xml = '<' + CrtLayoutElement.ROOT_CONTAINER + '>\n';

       for (var i=0; i<CrtLayoutElement.layoutSecPos.length; i++) {
            xml += CrtLayoutElement.layoutSections[CrtLayoutElement.layoutSecPos[i]].toXml();
        }

        xml += '</' + CrtLayoutElement.ROOT_CONTAINER + '>\n';
        return xml;
    }


    CrtLayoutElement.escapeXML = function(v) {
        v = v.replace(/&/g, '\&amp;');
        v = v.replace(/"/g, '\&quot;');
        v = v.replace(/'/g, "\'");
        v = v.replace(/</g, '&lt;');
        v = v.replace(/>/g, '&gt;');

        return v;
    }

   LayoutSection.prototype.toXml = function() {
        var xml = '<' + CrtLayoutElement.SECTION + ' ';
        //add sectionId
        xml += CrtLayoutElement.SECTION_ID + '=' + '"' + CrtLayoutElement.escapeXML(this.sectionValue) + '" ';
       //add sectionName
        xml += CrtLayoutElement.SECTION_NAME + '=' + '"' + CrtLayoutElement.escapeXML(this.labelName) + '" >\n';
        //iterate over all layout items and add them to xml
        for (var i=0; i < this.numRows; i++) {
            for (var j=0; j< this.numCols; j++) {
                if (!this.getItem(i,j).isEmpty) {
                    xml += '\t';
                    xml += this.getItem(i,j).toXml();
                }
            }
        }

        xml += '</' + CrtLayoutElement.SECTION + '>\n';
        return xml;
   }

   LayoutItem.prototype.toXml = function() {
        var xml = '<' + CrtLayoutElement.ITEM + ' ';
        //add itemId
        xml += CrtLayoutElement.ITEM_ID + '=' + '"' + CrtLayoutElement.escapeXML(this.fieldId) + '" ';
        //add itemName
        xml += CrtLayoutElement.ITEM_NAME + '=' + '"' + CrtLayoutElement.escapeXML(this.fieldName) + '" ';
        //add default selected
        xml += CrtLayoutElement.ITEM_DEFAULT_CHECKED + '=' + '"' + this.defaultChecked + '" ';
        //add custom label
        if (this.customName != null) {
            xml += CrtLayoutElement.ITEM_CUSTOMLABEL + '=' + '"' + CrtLayoutElement.escapeXML(this.customName) + '" ';
        }
        //add itemType
        xml += CrtLayoutElement.ITEM_TYPE + '=' + '"' + this.type + '" >';

        xml += '</' + CrtLayoutElement.ITEM + '>\n';
        return xml;
   }

   LayoutSection.prototype.getItem = function(rowNum,colNum) {
        return this.layoutItems[rowNum][colNum];
    }

    CrtLayoutElement.isMouseDown = function() {
        return CrtLayoutElement.mouseDown;
    }

     function LayoutSectionSeparator(divId, sectionId) {
         this.divId = divId;
         this.sectionId = sectionId;
         this.attachEvents();
         this.setHighlighted(false);
     }

     LayoutSectionSeparator.prototype.setHighlighted = function(isHighlighted) {
           this.isHighlighted = isHighlighted;
           this.formatSeparator();
           if (isHighlighted) {
                   CrtLayoutElement.highlightSec = this;
           } else {
                   CrtLayoutElement.highlightSec = null;
           }
     }

    LayoutSectionSeparator.prototype.attachEvents = function() {
         var self = this;
         addEvent(document.getElementById(self.divId), 'mouseover', function(evt) {self.handleMouseOver(evt);}, false);
    }

    LayoutSectionSeparator.prototype.handleMouseOver = function() {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && MoveableItem.currentSelectedObj.isSection) {
            if (CrtLayoutElement.highlightSec) {
                CrtLayoutElement.highlightSec.setHighlighted(false);
            }
            this.setHighlighted(true);
        }
    }

    //format a section separator
    LayoutSectionSeparator.prototype.formatSeparator = function() {
        var itemElem = document.getElementById(this.divId);
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR;
        if (this.isHighlighted) {
            className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_SECTION_SEPARATOR_HIGHLIGHT;
        }
        itemElem.className = className;
    }

     function setSeparatorAttributes(sectionId,elementId, rowPos, colPos, rowObj) {
        new LayoutItemSeparator(sectionId,elementId, rowPos,colPos, rowObj).insertField();
     }


     function LayoutItemSeparator(sectionId, elementId, rowPos, colPos, rowObj) {
         this.sectionId = sectionId;
         this.rowPos = rowPos;
         this.colPos = colPos;
         if (elementId == null) {
             this.itemElem  = rowObj.insertCell(rowObj.cells.length);
             this.id = this.createNewCellId();
             this.itemElem.id = this.id;
         }
         else {
            this.id = elementId;
         }
    }

    //insert a field into the Layout Section Object
    LayoutItemSeparator.prototype.insertField = function() {
        CrtLayoutElement.layoutSections[this.sectionId].insertSeparatorCell(this);
    }

    LayoutItemSeparator.prototype.handleMouseUp = function(evt) {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove) {
            var evt = getEvent(evt);
            CrtLayoutElement.layoutSections[this.sectionId].moveCells(this.rowPos,this.colPos);
            this.setHighlighted(false);
        }
    }

    LayoutItemSeparator.prototype.handleMouseOver = function() {
        if (CrtLayoutElement.mouseDown && CrtLayoutElement.dragMove && !MoveableItem.currentSelectedObj.isSection) {
            if (LayoutItemSeparator.highlightSep) {
                LayoutItemSeparator.highlightSep.setHighlighted(false);
            }
            this.setHighlighted(true);
        }
      }

       LayoutItemSeparator.prototype.setHighlighted = function(isHighlighted) {
           this.isHighlighted = isHighlighted;
           this.formatSeparator();
           if (isHighlighted) {
                   LayoutItemSeparator.highlightSep = this;
           } else {
                   LayoutItemSeparator.highlightSep = null;
           }
       }


    //format a separator
    LayoutItemSeparator.prototype.formatSeparator = function() {
        var className = CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR;
        if (this.isHighlighted) {
            className += ' ' + CrtLayoutElement.CSS_CLASS_LAYOUT_ITEM_SEPARATOR_HIGHLIGHT;
        }
        if (!this.itemElem) {
            this.itemElem = document.getElementById(this.id);
        }
        this.itemElem.className = className;
    }

    function escapeQuotes(v) {
        if (v && v.replace){
            v = v.replace(/'/g, "\'");
            v = v.replace(/"/g, '&quot;');
        }
        return v;
    }

    function doNothing(evt) {
        evt = getEvent(evt);
        eventCancelBubble(evt);
    }

   CrtLayoutElement.preview = function(url) {
        document.submitForm.val.value = CrtLayoutElement.toXML();
        openPopupFocus('', 'crtlayoutpreview', 700, 500,'location=no,dependent=no,resizable=yes,toolbar=no,status=no,directories=no,menubar=no,scrollbars=yes', true, false, false);
        borrowForm('submitForm', url, 'crtlayoutpreview');
   }

   CrtLayoutElement.getLookupFieldFromPath = function(path) {
    var primObjMData = CrtLookups.primaryObjects;
    var fieldsMData = CrtLookups.fields;

    var iFieldSep = path.lastIndexOf('.');
    var iSep = path.indexOf('.');
    var table = primObjMData[path.substring(0,iSep)].table;
    var lookup;
    while (iSep != iFieldSep) {
        lookup = path.substring(iSep+1,path.indexOf('.',iSep+1));
        table = fieldsMData[table][lookup].lookup;
        iSep = path.indexOf('.',iSep+1);
    }
    lookup = path.substring(iSep+1);
    return fieldsMData[table][lookup];
}



    CrtLayoutElement.getPath  = function(value) {
        return value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP));
    }

    //if isDisplayName, we use ":" separator notation, ">>" otherwise
    CrtLayoutElement.getDisplayPath = function(value, isDisplayName) {
        var path = '';
        path += CrtLayoutElement.getPrimObjMetaMap()[CrtLayoutElement.getPrimObjId(value,'.')].label + (isDisplayName ? ': ' : ' >> ');
        var table = CrtLayoutElement.getPrimObjMetaMap()[CrtLayoutElement.getPrimObjId(value,'.')].table;
        value = value.substring(value.indexOf('.')+1);
        var separator = isDisplayName ? ': ' : ' > ';
        var pathLabel;
        while (value.indexOf('.') > -1) {
            table = CrtLookups.fields[table];
            path += table[value.substring(0,value.indexOf('.'))].label + separator;
            table = table[value.substring(0,value.indexOf('.'))].lookup;
            value = value.substring(value.indexOf('.')+1);
        }
        table = CrtLookups.fields[table];
        path += table[value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP))].label + separator;
        table = table[value.substring(0,value.indexOf(CrtLayoutElement.FIELD_SEP))].lookup;

        path += CrtLookups.fields[table][value.substring(value.indexOf(CrtLayoutElement.FIELD_SEP)+1,value.indexOf(CrtLayoutElement.COL_SEP))].label;
        return path;
    }

    //return the AvailabaleSection based on the fieldValue we are given
CrtLayoutElement.getSectionFromFieldValue = function(fieldValue) {
    //kind of HACK way of knowing whether something is a lookup item for not...looking for path separator
    if (fieldValue.indexOf('.') > -1) {
        var primId = CrtLayoutElement.getPrimObjId(fieldValue,'.');
        return CrtLayoutElement.availableSections[CrtLookupSection.getSectionIdFromPrim(primId)];
    } else {
        var primId = CrtLayoutElement.getPrimObjId(fieldValue,CrtLayoutElement.FIELD_SEP);
        return CrtLayoutElement.availableSections[primId];
    }
}

CrtLayoutElement.getPrimObjId = function(path,separator) {
    if (!path) {
        return;
    }
    var iSep= path.indexOf(separator);
    if (iSep > 0) {
        path = path.substring(0,iSep);
        return path;
    } else {
        return null;
    }
}

   CrtLayoutElement.scrollAvailableSection = function(evt){
        var cru = document.getElementById(CrtLayoutElement.SECTION_AVAIL_WRAPPER_ID);
        if (cru) {
            var topValue;
             if(!CrtLayoutElement.availableSectionPosInited) {
                CrtLayoutElement.availableSectionInitPosY = getObjY(cru);
                cru.style.top = '0px';
                CrtLayoutElement.availableSectionPosInited = true;
                return;
            }
            var initLeftHeight = document.getElementById(CrtLayoutElement.LEFT_SECTION_ID).offsetHeight;
            var initRightHeight = document.getElementById(CrtLayoutElement.SECTION_AVAIL_WRAPPER_ID).offsetHeight;
            maxTopValue = initLeftHeight;
            //don't scroll it till it goes offscreen
            if(CrtLayoutElement.availableSectionInitPosY+5 < getScrollY()){
                topValue = getScrollY();
                if (topValue + initRightHeight - 295 < initLeftHeight) {
                   cru.style.top = topValue - 295 + "px";
                //if we are at the bottom of the layout sections, then no more scrolling
                } else {
                    cru.style.top = initLeftHeight-initRightHeight + "px";
                }
            } else {
                cru.style.top = "0px";
            }
        }

    }


var Util = {
    makeOptionString : function(labelText, value, array){
        if (!array){
            return "<option value='" + value + "'>" + labelText + "</option>";
        } else {
            array.push('<option value="')
            array.push(value);
            array.push('">');
            array.push(labelText);
            array.push('</option>');
        }
    },
    
    scriptCache : {},

    evalScriptsUnderElement : function(element){
        var scriptTags = element.getElementsByTagName("script");
        var srcScripts = [];
        for (var i = 0; i < scriptTags.length; i++) {
        	var src = scriptTags[i].src;
        	if (src && !Util.scriptCache[src]) {
        		XBrowser.createDynamicScript(src);
        		Util.scriptCache[src] = true;
        		srcScripts.push(scriptTags[i]);
	     	} else {
	            eval(scriptTags[i].innerHTML);
        	}
        }
        for (var i = 0; i < srcScripts.length; i++) {
   			srcScripts[i].parentNode.removeChild(srcScripts[i]);	
        }
    },

    /**
     * Load javascript of the element
     */
    evalScriptsUnderElementWithSrc : function(element){
        // local function of parsing javascript
        var _parseScripts = function(){
            // get the colletion of script elements
            var scriptTags = element.getElementsByTagName("script");

            // get the header element
            var docHead = document.getElementsByTagName("head")[0];

            // for each script element, check if it is linked to external js file like <script src=...> or, a local script body
            for(var scriptIndex = 0; scriptIndex < scriptTags.length; scriptIndex++){
                // create a new script element and assign the type
                var newScript = document.createElement("script");
                newScript.type = scriptTags[scriptIndex].type;

                // if the script is linked to external js file, the src value is not null. In this case, using AJAX to fecth the script body and evaluate
                if (scriptTags[scriptIndex].src) {
                    // using AJAX to get the script body
                    var xmlHttp = XBrowser.createHttpRequest();
                    xmlHttp.open("GET" ,scriptTags[scriptIndex].src ,false);
                    xmlHttp.send(null);

                    // eval the script
                    eval(xmlHttp.responseText);
                    newScript.src = scriptTags[scriptIndex].src;

                    // add it to header
                    docHead.appendChild(newScript);
                } else if(scriptTags[scriptIndex].text) {
                    // if the script is local script, eval the script and add it to header
                    eval(scriptTags[scriptIndex].text);
                    newScript.text = scriptTags[scriptIndex].text;
                    docHead.appendChild(newScript);
                } else {}
            }
        }
        // set timeout to give DOM opportunity to catch up
        setTimeout(_parseScripts, 0);
    },

    evalAjaxServletOutput : function(jsonStr){
        if (!jsonStr){
            return null;
        } else if (jsonStr.substring(0, AjaxServlet.CSRF_PROTECT.length) !== AjaxServlet.CSRF_PROTECT){
            //If it doesn't start with CSRF_PROTECT, it didn't come from AjaxServlet...something's wrong
            throw "CSRF protect string not added to servlet response.";
        } else  {
            return eval('('+jsonStr.substring(AjaxServlet.CSRF_PROTECT.length, jsonStr.length) + ')');
        }
    },

    refreshDynamicSelect : function(/*SelectElement*/selectElement, /*list of [label, value]*/options, /*boolean*/ showNone, /*str*/valToMatch){
        var selectedIndex = 0;
        var optionsArr = ["<select name='", selectElement.name, "' id='", selectElement.id, "' class='", selectElement.className, "' title='", selectElement.title, "'"];
        // otherAtributes contains optional attributes for select elements, they are retained if they are set for the original element
        var otherAttributes = ["size","multiple"];
        for (var i = 0; i < otherAttributes.length; i++){
            var param=otherAttributes[i];
            if (selectElement[param]) {
                optionsArr.push(" ");
                optionsArr.push(param);
                optionsArr.push("='");
                optionsArr.push(selectElement[param]);
                optionsArr.push("'");
            }
        }
        optionsArr.push(">");

        var indexNum = 0;
        if (showNone){
            Util.makeOptionString(LC.getLabel("SelectElement", "Required"), '', optionsArr);
            indexNum++;
        }
        for (var i = 0; i < options.length; i++){
            var newVal = options[i][1];
            Util.makeOptionString(options[i][0], newVal, optionsArr);
            if (valToMatch && (newVal === valToMatch)){
                selectedIndex = indexNum;
            }
            indexNum++;
        }
        optionsArr.push("</select>");
        var selParent = selectElement.parentNode;
        if (!selParent.isDynamicSelect){
            var wrapperSpan = document.createElement("SPAN");
            wrapperSpan.isDynamicSelect = true;
            selParent.insertBefore(wrapperSpan, selectElement);
            selParent.removeChild(selectElement);
            selParent = wrapperSpan;
        }
        selParent.innerHTML = optionsArr.join("");
        var newSel = selParent.firstChild;
        if (valToMatch){
            newSel.selectedIndex = selectedIndex;
        }
        return newSel;
     },
 /**
  * Will return a string that can be used as the innerHTML of another element, which will
  * create a select element with the desired attributes and options
  */
    createDynamicSelect : function(/*attribute map*/attributeMap, /*list of [label, value]*/options, /*boolean*/ showNone) {
        var optionsArr = ["<select"];
        for (var key in attributeMap){
                optionsArr.push(" ");
                optionsArr.push(key);
                optionsArr.push("='");
                optionsArr.push(attributeMap[key]);
                optionsArr.push("'");
        }
        optionsArr.push(">");

        if (showNone){
            Util.makeOptionString(LC.getLabel("SelectElement", "Required"), '', optionsArr);
        }
        for (var i = 0; i < options.length; i++){
            var newVal = options[i][1];
            Util.makeOptionString(options[i][0], newVal, optionsArr);
        }
        optionsArr.push("</select>");

        return optionsArr.join("");
    },

    /**
     * convenience method to add Options to SelectElements
     */
    insertOption : function(/*Select Element*/ selectElement, /* Option Element */ optionElement, /* int */index) {
        if (selectElement.currentStyle) {
            selectElement.add(optionElement, index);
        } else {
            selectElement.add(optionElement, selectElement.options[index]);
        }
    },

    /**
     * converts a list of options in [label, value] format into the format used by the picklist/MSP code
     */
    convertOptionsForPicklistData : function(/* list of [label, value] */ options) {
        var ret = [];
        for (var i = 0; i < options.length; i++) {
            ret.push(options[i][1]);
            ret.push(options[i][0]);
        }
        return ret;
    },

    /**
     * animates an HTMLElement by continuously altering a specified CSS value
     *
     * a sample argument template for your coding convenience:
     * {"obj":object, "prop":"propertyName", "start":start, "target":target, "f":function(n) {return n}, "maxinc":maxinc, "aftereach": function(){...}, "after":function(){...}}
     *
     * NOTE: for opacity, specify a value between 0 and 100 (IE style), not between 0.0 and 1.0 (Firefox style)
     *
     */
    animate : function(args) {
        var obj = args["obj"];						/* element */
        var prop = args["prop"];					/* css property to change, as a string */
        var value = parseInt(args["start"]);		/* start value */
        var target = args["target"];				/* target value */
        var f = args["f"] || function(n){return n};	/* optional approach function, defaults to linear */
        var inc = args["inc"] || 1;					/* optional current increment (specify to give starting speed) */
        var maxinc = args["maxinc"] || Infinity;	/* optional maximum increment (i.e., when to stop acceleration) */
        var after = args["after"];					/* optional function to call when animation is complete */
        var aftereach = args["aftereach"];			/* optional function to call after each frame of animation */

        if (target < value) {
            var dest = value - f(inc);
            value = (dest < target) ? target : dest;
        }
        else if (target > value) {
            var dest = value + f(inc);
            value = (dest > target) ? target : dest;
        }

        if(prop=="opacity") {
            obj["style"][prop] = value / 100;
            obj["style"]["filter"] = "alpha(opacity="+value+")";
        } else {
            obj["style"][prop] = value + "px";
        }

        if (!(inc >= maxinc))
            inc++;

        if (value != target) {
            if (aftereach)
                aftereach();
            setTimeout(function () { Util.animate({"obj":obj, "prop":prop, "start":value, "target":target, "f":f, "aftereach":aftereach, "after":after, "inc":inc}) }, 20);
        } else {
            if (aftereach)
                aftereach();
            if (after)
                setTimeout(after, 50);
        }
    }
}


var CalCnC = {
    enabled : false,
    editNewEventDialog : "",
    isAllDay : null,
    startDate : null,
    startTime : null,
    actionUrl : null,
    eventMiniEditElementIdsJson : null,
    editPageUrlBase : null, // retURL is original page url - not current state
    editPageUrl : null,     // retURL modified to reflect current state in editNewEventHandler
    // Propagate errors from dialog to edit page when following link
    // After dismissing the dialog this flag must be reset to false.
    // There are currently 3 ways to dismiss the dialog:
    // 1. Click Save
    // 2. Click Cancel
    // 3. Follow link to edit page
    propagateErrorsToEditPage : null,
    initialHeight: null,
    initialWidth: 1,
    loading : null,
    datePickerParent : null,
    loadingShim: null,

    init : function(actionUrl, eventMiniEditElementIdsJson, editPageUrl) {
        if (CalCnC.enabled) {
            return; // don't init more than once
        }
        CalCnC.editNewEventDialog = new SimpleDialog("editNewEventDialog", true);
        CalCnC.editNewEventDialog.extraClass = "clickAndCreateDialog";
        // add close [X] button show up in pop up dialog
        // Set this property before the page loads - onload registration reads this variable
        CalCnC.editNewEventDialog.displayX = true;
        CalCnC.editNewEventDialog.register();

        // Overwrite the function to catch window's resize event
        CalCnC.editNewEventDialog.resizeEvent = function() {
          // get the HTML element of editNewEventDialog
          var dialogHTMLElement = document.getElementById('editNewEventDialog');

          var visibleFlag = true;
          if(dialogHTMLElement && dialogHTMLElement.currentStyle) {
            if (dialogHTMLElement.currentStyle.visibility=='hidden') {
              visibleFlag = false;
            }
          } else {
            if(dialogHTMLElement && dialogHTMLElement.style && dialogHTMLElement.style.visibility =='hidden') {
              visibleFlag = false;
            }
          }
          if (visibleFlag) {
            // set the dialog's height according to broswer's height
            CalCnC.setDialogSize();
          }

          // call parent's resize function
          OverlayDialog.prototype.resizeEvent.call(this);
        };

        // overwrite cancel function to call CalCnC.cancelHander
        CalCnC.editNewEventDialog.cancel = function() {
            CalCnC.cancelHandler();
        };

        window.sfdcPage.appendToOnloadQueue(function() {CalCnC.onloadHandler(actionUrl, eventMiniEditElementIdsJson, editPageUrl);}, "Setup click and create");
    },

    onloadHandler : function(actionUrl, eventMiniEditElementIdsJson, editPageUrl) {
        CalCnC.actionUrl = actionUrl;
        CalCnC.eventMiniEditElementIdsJson = eventMiniEditElementIdsJson;
        CalCnC.editPageUrlBase = editPageUrl;

        var arr = [];
        arr.push(CalCnC.actionUrl);
        arr.push('?isAjaxRequest=1');
        CalCnC.actionUrl = arr.join('');

        CalCnC.editNewEventDialog.setTitle(LC.getLabel("Page_Event", "page_title_new"));

        CalCnC.propagateErrorsToEditPage = false;
        CalCnC.enabled = true;
    },

    editNewEventHandler : function(userId, username, startDate, startTime, whoWhatId, isWho, isWhat) {
        if(CalCnC.enabled) {
            isAllDay = startTime == null;
            var arr = [];
            arr.push(CalCnC.actionUrl);
            arr.push("&aid=");
            arr.push(userId);
            arr.push("&anm=");
            arr.push(username);
            arr.push("&evt4=");
            arr.push(startDate);
            arr.push("&RecurrenceStartDateTime=");
            arr.push(startDate);
            if (isAllDay) {
                arr.push("&evt15=1");
            } else {
                arr.push("&evt13=");
                arr.push(startTime);
            }
            if (whoWhatId) {
				if (isWho == true) {
					arr.push("&who_id=");
					arr.push(whoWhatId);
				}
                if (isWhat == true) {
                    arr.push("&what_id=");
					arr.push(whoWhatId);
                } 
            }
            // pass in a retURL so we don't get default - the form's retURL & cancelURL get passed in goToFullEditPageHandler
            arr.push("&");
            arr.push(UiData.pRET_URL);
            arr.push("=");
            arr.push(CalFunctions.returnUrlProvider());
            var miniPageUrl = arr.join('');

            // this gets used by the link to full edit page
            CalCnC.editPageUrl = CalFunctions.fixReturnUrl(CalCnC.editPageUrlBase);

            // create the loadingScreen object and display the loading screen
            // editNewEventDialog_Loading: the id of the new created loading element
            // bodyCell - the ID of the body part of the page
            if (!CalCnC.loading)
                CalCnC.loading = new LoadingScreen(document.getElementById(SidebarConstants.SIDEBAR_DIV_ID).parentNode, LC.getLabel("Global", "loading"), "editNewEventDialog_Loading");
            CalCnC.showLoadScreen(CalCnC.loading);

            XBrowser.getHttpResponse(miniPageUrl, CalCnC.formGetHandler, CalCnC.formErrorHandler);
        }
    },

    // Show loading screen
    showLoadScreen : function(loadSaveScreen) {
        if (!CalCnC.loadingShim) {
            var loadingDiv = document.getElementById(SidebarConstants.SIDEBAR_DIV_ID).parentNode;
            CalCnC.loadingShim = new iframeShim(loadingDiv);
        }

        //set the shim's width and height to be 100%
        CalCnC.loadingShim.setStyle("width", "100%");
        CalCnC.loadingShim.setStyle("height", "100%");

         // if the broswer is IE 6, set zIndex value
        if (XBrowser.userAgent.isIE6) {
            CalCnC.loadingShim.iframe.style.zIndex = 50;
        }
        loadSaveScreen.show();
    },

    // Hide loading screen
    hideLoadScreen : function(loadSaveScreen) {
        if (CalCnC.loadingShim) {
            // if the broswer is IE 6, set zIndex value
            if (XBrowser.userAgent.isIE6) {
                CalCnC.loadingShim.iframe.style.zIndex = -1;
            }
        }
        loadSaveScreen.hide();
    },

    formGetHandler : function(request) {
      if(CalCnC.enabled) {
        if (!CalCnC.isDisplayingForm(request)) {
            CalCnC.formErrorHandler(request);
            return;
        }

        // DatePicker.datePicker is a static variable and only allowed one per page.
        // If DatePicker.datePicker already exists before CnC dialog show up, set it to null.
        if (DatePicker.datePicker) {
          DatePicker.datePicker = null;
        }

        // displayFormContent returns true if the form displayed ok. 
        // In the case of problems displaying, it handles displaying an error msg. On error, no followup rendering is required. 
        if (CalCnC.displayFormContent(request)) {
	        // remember the inital height value of the dialog
	        if (CalCnC.initialHeight == null) {
	          CalCnC.initialHeight = document.getElementById('editNewEventDialog').scrollHeight;
	        }
	
	        // get the HTML element of editNewEventDialog
	        var dialogHTMLElement = document.getElementById('editNewEventDialog');
	
	        // hide the loading screen
	        CalCnC.hideLoadScreen(CalCnC.loading);
	
	        // set the height of the dialog
	        CalCnC.setDialogSize();
	
	        // Set focus on Subject.
	        // For IE, needs to be called twice (?) otherwise Subject does not get the focus. 
	        Ext.get('evt5').focus();
	        if (XBrowser.userAgent.isIE)
	        	Ext.get('evt5').focus();
      	}
      }
    },

    formErrorHandler : function(request) {
      if(CalCnC.enabled) {
        // hide the saving and loading screen
        if (CalCnC.loading)
          CalCnC.hideLoadScreen(CalCnC.loading);
        var arr = [];
        arr.push('<div id="overlayErrorId" class="overlayError">');
        arr.push('<div class="errorText">');
        arr.push(LC.getLabel('Page_Schedule', 'click_and_create_error'));
        arr.push('</div>');
        arr.push('<div class="buttons">');
        arr.push('<input type="button" onclick="window.location.reload();" name="miniOk" class="btn" value="');
        arr.push(LC.getLabel('Buttons', 'ok'));
        arr.push('"/>');
        arr.push('</div>');
        arr.push('</div>');
        CalCnC.editNewEventDialog.setContentInnerHTML(arr.join(''));

        document.getElementById('editNewEventDialogX').style.visibility = 'hidden';

        // set the dialog content height to be error message div height
        var dialogContentElement = document.getElementById('editNewEventDialogContent');
        dialogContentElement.style.height = "auto";

        CalCnC.editNewEventDialog.positioned = false;
        CalCnC.editNewEventDialog.position();
        if(!CalCnC.editNewEventDialog.dialog.style.visibility || CalCnC.editNewEventDialog.dialog.style.visibility == 'hidden') {
            CalCnC.editNewEventDialog.setWidth(OverlayDialog.MIN_WIDTH);
            CalCnC.editNewEventDialog.show();
        }
      }
    },

    displayFormContent : function(request) {
      if(CalCnC.enabled) {
        // add a line breaker using regexp before <script tag to fix the problem that IE will strip out script tag for innerHTML
        var miniPageHtml = request.responseText.replace(/(&nbsp;|\s)*<script/,"&nbsp;\n<script");

        // set content inner HTML for editNewEventDialog
        CalCnC.editNewEventDialog.setContentInnerHTML(miniPageHtml);

        document.getElementById('editPage').onsubmit = function() {
            CalCnC.saveNewEventHandler();
            return false;
        };

        // Handle click on the 'X' on the dialog header
        document.getElementById('editNewEventDialogX').onclick = function() {
            CalCnC.editNewEventDialog.cancel();
            return false;
        };

        // initialize the element ids
        if (CalCnC.eventMiniEditElementIdsJson) {
            ActivityFunction.initMiniPage(CalCnC.eventMiniEditElementIdsJson);
        }
      }

      // Let setDialogSize expand the dialog to the correct width
      CalCnC.editNewEventDialog.setWidth(CalCnC.initialWidth);

      // Evaluate the included javascript functions
      Util.evalScriptsUnderElementWithSrc(document.getElementById('editNewEventDialog'));

      // Overwrite the form ("editPage")'s action URL, to prevent the submit function direct page to MiniPage when
      // user clicks "Enter"
      document.getElementById(EditPageConstants.pEDIT_PAGE).action = "";

      // get the HTML content element of editNewEventDialog
      var dialogHTMLContentElement = document.getElementById('editNewEventDialogContent');

      // get the HTML element of datePicker
      var datePickerHTMLElement = document.getElementById('datePicker');

      // save original parent node so we can put this back
      CalCnC.datePickerParent = datePickerHTMLElement.parentNode;

      // append date picker to be a child of dialog element
      dialogHTMLContentElement.appendChild(datePickerHTMLElement);

      // pass in the parent element of the help to be editNewEventDialog
      var localSfdcPage = window.sfdcPage;
      localSfdcPage.setHelpParent(dialogHTMLContentElement);
      localSfdcPage.showHelp = function(id, element){
        GenericSfdcPage.prototype.showHelp.call(this, id, element);
        this.displayDiv.style.top = (getObjY(element) + element.offsetHeight + 8 - getObjY(dialogHTMLContentElement)) + 'px';
      }

	  // Return false if the form doesn't seem to be well formed.
      // Check if well-formed by verifying that an on-every-layout field, Subject, is present.
      // Not present indicates that perhaps 200 response did not have the expected content or was truncated. 
      if (!Ext.get('evt5')) {
    	  CalCnC.formErrorHandler();
    	  return false;
      }

      // Force dialog to re-center
      CalCnC.editNewEventDialog.positioned = false;
      CalCnC.editNewEventDialog.show();

      // Return true => form displayed properly
      return true;
    },


    /**
     *  Overwrite the function to catch window's resize event
     */
    setDialogSize: function () {
      // get the DOM object of dialogElement, editNewEventDialogContent and ep (which is the bottom div containing "save" and "cancel" button)
      var dialogElement = document.getElementById('editNewEventDialog');
      var dialogContentElement = document.getElementById('editNewEventDialogContent');
      var epElement = document.getElementById('ep');

      // set padding value, offset to broswer value and scrollbar value
      var dialogPadding = 20;
      var offsetToBrowser = 50;
      var scrollBarSize = 20;

      // if dialogElement is null or dialogContentElement is null, return
      if (!dialogElement || !dialogContentElement) {
          return;
      }

      // if the dialog is hidden, return
      if (!Ext.get(dialogElement).isVisible()) {
        return;
      }

      // set the overflowX property of dialogElement to be auto to get dialog scroll width
      dialogElement.style.overflowX = "auto";

      // if CalCnC.initialWidth is 1, it is first time to bring up the dialog, set the initial width, when scroll width exists
      if (CalCnC.initialWidth == 1 && dialogElement.scrollWidth > 0 ) {
          // resize the dialog, to be the scroll width + padding
          CalCnC.initialWidth = dialogElement.scrollWidth + dialogPadding + dialogPadding  ;
      }

      // set overflow property of dialogContentElement to be auto, and position to be relative (this resolves IE problem when the child element is relative and
      // parent is scrollable, elements messes up)
      dialogContentElement.style.position = "relative";
      dialogContentElement.style.overflow = "auto";

      // get the current window's width
      var currentWindowWidth = getWindowWidth();

      // set the maxium dislay width for the dialog to be window's width - 50 left offset - 50 right offset
      var maxDislayWidth = currentWindowWidth;
      if (currentWindowWidth > offsetToBrowser + offsetToBrowser ) {
          maxDislayWidth = currentWindowWidth - offsetToBrowser - offsetToBrowser;
      }

      // get dialog's display width, if initialWidth is larger than max display width, use max display width
      var dialogDisplayWidth = CalCnC.initialWidth > maxDislayWidth ? maxDislayWidth : CalCnC.initialWidth;

      // set the dialog's width
      CalCnC.editNewEventDialog.setWidth(dialogDisplayWidth + "px");

      // set the inner element's width to be dialogDisplayWidth - scroll bar width
      dialogContentElement.style.width = dialogDisplayWidth - scrollBarSize + "px";
      // set the bottom div ("save", "cancel" button) width to be orginal width
      epElement.style.width = CalCnC.initialWidth - dialogPadding - dialogPadding + "px";

      // get the current window's height
      var currentWindowHeight = getWindowHeight();

      // set the maxium dislay height for the dialog to be window's height - 50 offset to top - 50 offset to bottom
      var maxDislayHeight = currentWindowHeight;
      if (currentWindowHeight > offsetToBrowser + offsetToBrowser ) {
          maxDislayHeight = currentWindowHeight -offsetToBrowser - offsetToBrowser;
      }

      // get the dialog header's height, and the dialog's padding
      var formObj = Ext.get(Ext.getDom('editPage'));
      var headerHeight = Ext.get(dialogContentElement).getOffsetsTo(Ext.get(dialogElement))[1];
      var paddingHeight = formObj.getOffsetsTo(Ext.get(dialogContentElement))[1];

      // set the dialog display height to be form height + header height + padding
      var displayAreaHeight = formObj.getHeight() + paddingHeight + headerHeight ;

      var heightControllingElement = dialogContentElement;

      // for safari, set the height of editNewEventDialogInner instead of editNewEventDialogContent. This fixes the problem that
      // for first time CnC dialog is invoked, the dialog shows up as a grey box until you move over it
      if (XBrowser.userAgent.isSafari) {
          heightControllingElement = document.getElementById('editNewEventDialogInner');
      }

      // if the display height is larger than maxDisplayHeight, set the content height to be maxDislayHeight - headerHeight
      if (displayAreaHeight > maxDislayHeight) {
          heightControllingElement.style.height = maxDislayHeight - headerHeight  + "px";
      } else {
          heightControllingElement.style.height = formObj.getHeight() + paddingHeight + scrollBarSize + "px";
      }

      dialogElement.style.overflow = "hidden";
    },

    saveNewEventHandler : function(startDate, startTime, request) {
      var formElement = document.getElementById(EditPageConstants.pEDIT_PAGE);
      postBody = CalCnC.extractPostBody(formElement, true);

      CalCnC.disableButtons();

      // Ensure that any errors from the dialog are displayed on the edit page if link is followed
      CalCnC.propagateErrorsToEditPage = true;
      var request = XBrowser.postHttpResponse (CalCnC.actionUrl, CalCnC.formSubmitHandler, postBody, CalCnC.formErrorHandler);
    },

    cancelHandler : function () {
      CalCnC.clearState(true);
      CalCnC.editNewEventDialog.hide();
    },

    // @param save whether or not qs will cause a save to happen, i.e. save from dialog vs nav to edit page
    extractPostBody : function (formElement, save) {
      var qs = Ext.Ajax.serializeForm(formElement);
      if (!save) {
        qs = qs.replace(/&save=[^&]*&/g, '&');
        qs = qs.replace(/&save=[^$]*$/g, '');
        if (!CalCnC.propagateErrorsToEditPage) {
          // Remove parameters with no values. No need to display errors for empty required fields in edit page since no save attempt has happened
          qs = qs.replace(/&[^=]*=&/g, '&');
          qs = qs.replace(/&[^=]*=$/g, '');
        }
      }
      return qs;
    },

    formSubmitHandler : function(request) {
      if(CalCnC.enabled) {
        if (CalCnC.isDisplayingForm(request)) {
          // The dialog must be redisplayed. Perhaps validation failed.
            // displayFormContent returns true if the form displayed ok. 
            // In the case of problems displaying, it handles displaying an error msg. On error, no followup rendering is required. 
            if (CalCnC.displayFormContent(request)) {
  	          // set the height of the dialog
  	          CalCnC.setDialogSize();
  	
  	          // Set focus on Subject. Do this after hiding loading screen so cursor appears properly
  	          Ext.get('evt5').focus();
  	
  	          var dialogContent = document.getElementById('editNewEventDialogContent');
  	          dialogContent.scrollTop = 0;
            }
        } else {
          // The dialog save worked. Hide and refresh the calendar.
          CalCnC.clearState(true);

          CalCnC.editNewEventDialog.hide();
          refreshCalendar(); // calendar actionFunction
        }
      }
    },

    isDisplayingForm : function (request) {
      var oldInnerHTML = CalCnC.editNewEventDialog.getContentElement().innerHTML;
      CalCnC.editNewEventDialog.setContentInnerHTML(request.responseText);
      var formFound = document.getElementById(EditPageConstants.pEDIT_PAGE) != null;
      CalCnC.editNewEventDialog.setContentInnerHTML(oldInnerHTML);
      return formFound;
    },

    // Clear any state that shouldn't be preserved between summonings of the dialog from the calendar
    // This method not to be called when redisplaying dialog after a failed save
    clearState : function(clearDialogContents) {
      // make sure the date picker is hidden
      if (DatePicker.datePicker) {
        DatePicker.datePicker.hide();
      }
      // put the date picker back where we found him
      var datePickerHTMLElement = document.getElementById('datePicker');
      CalCnC.datePickerParent.appendChild(datePickerHTMLElement);

      CalCnC.propagateErrorsToEditPage = false;
      if (clearDialogContents) {
        CalCnC.editNewEventDialog.setContentInnerHTML('');
      }
    },

    disableButtons : function() {
        var miniSave = document.getElementById('miniSave');
        miniSave.disabled = true;
        miniSave.className = 'btnDisabled';
        var miniCancel = document.getElementById('miniCancel');
        miniCancel.disabled = true;
        miniCancel.className = 'btnDisabled';
        var editPageLink = document.getElementById('miniEditPageLink');
        editPageLink.onclick = function() {
            return false;
        };
    },

    // This gets called from an onclick handler added in EventPage.java
    // it requires that CalCnC.editPageUrl has been set properly in editNewEventHandler
    goToFullEditPageHandler : function() {
        var formElement=document.getElementById(EditPageConstants.pEDIT_PAGE);
        var arr=[];
        arr.push(CalCnC.editPageUrl);
        arr.push('&');
        arr.push(CalCnC.extractPostBody(formElement,false));
        var target=arr.join('');
        CalCnC.clearState(false);
        location.href=target;
    }
}

/**
  PickableMotifElement mirrors the java class of the same name
  It is a subclass of MotifElement & is used on MotifPicker.java

  @author polcari
  @since 144


  @param motifElementId - The motifElement that this is attached to
  @param motifInputElementId - the parent's param
*/
function PickableMotifElement(id, descCellId, iconId, _motifKey, motifInputElementId) {
  this.init(id, descCellId, iconId, _motifKey); //superclass c'tr
  var self = this;
  if (window.opener) {
    this.parentMotifInputElementObj = window.opener.document.getElementById(motifInputElementId).motifInputElement;
  }
  this.motifElement.onclick = function () {
    //copy class
    self.parentMotifInputElementObj.motifElement.className = self.motifElement.className;
    //copy cell text
    self.parentMotifInputElementObj.setDescription(self.getDescription());
    //copy icon
    if (self.motifIcon && self.motifIcon.src) {
      self.parentMotifInputElementObj.setIconSrc(self.motifIcon.src);
      self.parentMotifInputElementObj.setIconValue('');
    }
    //copy input box
    self.parentMotifInputElementObj.setMotifKey(self.motifKey);
    window.blur();
    window.close();
    return false;
  };
}

//subclass of MotifElement
PickableMotifElement.prototype = new MotifElement;

//static function used on the motifpicker
PickableMotifElement.toggleUsedMotifVisibility = function(showThem) {
  var allMotifs = document.getElementsByTagName("a");

  for (var i = 0; i < allMotifs.length; i++) {
    if ((showThem) && (allMotifs[i].style.display == 'none') && (allMotifs[i].className.indexOf('motifElement') > -1)) {
      allMotifs[i].style.display = 'block';
    } else if ((!showThem) && (allMotifs[i].className) && (allMotifs[i].className.indexOf('usedMotif') > -1)) {
      allMotifs[i].style.display = 'none';
    }
  }
}

PickableMotifElement.hideUsedStyle = function() {
  document.getElementById("hideUsedStyle").style.display = 'none';
  document.getElementById("showUsedStyle").style.display = 'block';
  PickableMotifElement.toggleUsedMotifVisibility(false);
  return false;
}

PickableMotifElement.showUsedStyle = function() {
  document.getElementById("showUsedStyle").style.display = 'none';
  document.getElementById("hideUsedStyle").style.display = 'block';
  PickableMotifElement.toggleUsedMotifVisibility(true);
  return false;
}

var PortalStyleConfigEditor = {
    themes: {},
    themeLoader: null,
    previewUrls: {},
    inputs: []
};

PortalStyleConfigEditor.updateAllPreviews = function () {
    for (key in this.previewUrls) {
        this.updatePreview(this.previewUrls[key], key);
    }
};


PortalStyleConfigEditor.ThemeLoader = function (id) {
    this.id = id;
    this.select = document.getElementById(id);

    var self = this;
    this.handleChange = function (e) {
        self.loadTheme();
    }

    this.init();
};

PortalStyleConfigEditor.ThemeLoader.prototype.loadTheme = function () {
    var newTheme = this.select.value;
    var styleMap = PortalStyleConfigEditor.themes[newTheme];
    for (key in styleMap) {
        var field = document.getElementById(key);
        field.value = styleMap[key];
        if (field.updateColor) {
            field.updateColor();
        }
    }
    this.select.value = newTheme;
    PortalStyleConfigEditor.updateAllPreviews();
};

PortalStyleConfigEditor.ThemeLoader.prototype.reset = function () {
    this.select.value = "";
};

PortalStyleConfigEditor.ThemeLoader.prototype.init = function () {
    addEvent(this.select, 'change', this.handleChange, false);
    PortalStyleConfigEditor.themeLoader = this;
};

PortalStyleConfigEditor.FontSizeInputElement = function (id) {
    this.id = id;
    this.input = document.getElementById(id);

    var self = this;
    this.handleChange = function (e) {
        self.formatInput();
    };

    this.init();
};

PortalStyleConfigEditor.FontSizeInputElement.prototype.formatInput = function () {
    var fontSize = this.input.value;
    if ("%" != fontSize.charAt(fontSize.length - 1)) {
        this.input.value = fontSize + "%";
    }
};

PortalStyleConfigEditor.FontSizeInputElement.prototype.init = function () {
    addEvent(this.input, "change", this.handleChange, false);
};

PortalStyleConfigEditor.CssWidthInputElement = function (id) {
    this.id = id;
    this.select = document.getElementById(id);
};

PortalStyleConfigEditor.FontFamilyInputElement = function (id) {
    this.id = id;
    this.select = document.getElementById(id);
};


PortalStyleConfigEditor.BorderStyleInputElement = function (id) {
    this.id = id;
    this.input = document.getElementById(id);
};

PortalStyleConfigEditor.getPostBody = function () {
    var params = {};
    for (var i = 0; i < this.inputs.length; i++) {
        var input = this.inputs[i];
        params[input.id] = input.value;
    }

    return XBrowser.buildPost(params);
};

PortalStyleConfigEditor.updatePreview = function (url, target) {
    var handler = function (r) {
        var iframe = document.getElementById(target);
        var doc = iframe.contentWindow || iframe.contentDocument;
        if (doc.document) { doc = doc.document;}
        doc.body.innerHTML = "";
        doc.write(r.responseText);
        doc.close();
        iframe.style.height = doc.body.offsetHeight + "px";
    };
    var postBody = this.getPostBody();
    XBrowser.postHttpResponse(url, handler, postBody);
};

PortalStyleConfigEditor.init = function () {
    var tmp = document.getElementById(EditPageConstants.pEDIT_PAGE).elements;
    var handler = function (e) {
        PortalStyleConfigEditor.themeLoader.reset();
        PortalStyleConfigEditor.updateAllPreviews();
    };
    for (var i = 0; i < tmp.length; i++) {
        var field = tmp[i];
        if (0 == field.id.indexOf(PortalStyleConfigEditorConstants.PARAM_PREFIX)
            && field.id != this.themeLoader.id) {
            addEvent(field, "change", handler);
            this.inputs.push(field);
        }
    }
};

function CustomEntityDefinition(selectElemId, radioName) {
	//If the the select doesn't exist, we don't need anything else (might be a managed entity)
	if (!document.getElementById(selectElemId)){
		return;
	}
    this.picker = selectElemId;
    this.radioName = radioName;

    var self = this;

    this.enableScontrolPicker = function(e) {
        var radio = getEventTarget(getEvent(e));
        document.getElementById(selectElemId).disabled = (radio.value == "1" ? false : true);
        document.getElementById(selectElemId).value = (radio.value == "1" ? document.getElementById(selectElemId).value : "");
    }

    var radios = document.getElementsByName(this.radioName);

    for( var i=0; i<radios.length; i++){
        addEvent(radios[i], "click", this.enableScontrolPicker, false);
    }

    document.getElementById(selectElemId).disabled = (document.getElementById(selectElemId).value == "" ? true : false);

}

CustomEntityDefinition.handleAutoNumberSel = function(s,e1,e2) {
    var b =s.selectedIndex == 0;
    toggleRow(e1, !b);
    if (e2) toggleRow(e2, !b);
}
CustomEntityDefinition.hasAlerted = false;
CustomEntityDefinition.displayFormatChangeWarning = function() {
    if (!CustomEntityDefinition.hasAlerted) {
        alert(LC.getLabel('Page_CustomEntityDefinition_Edit', 'DisplayFormatChangeWarning'));
        CustomEntityDefinition.hasAlerted = true;
    }
}

CustomEntityDefinition.setNameLabel = function(masterLabel, nameElem) {
    if (nameElem.value.length == 0 && masterLabel.value.length != 0) {
        var max = nameElem.maxLength;
        var targetVal = LC.getLabel('Page_CustomEntityDefinition_Edit', 'DefaultNameLabel', masterLabel.value);
        if (targetVal.length > max){
            targetVal = targetVal.substring(0, max);
        }
        nameElem.value = targetVal;
    }
}


/**
 * Javascript object and controls for the inline color picker
 * @author rchen
 * @since 148
 */
 function ColorPicker() {
     this.pickerDiv = document.getElementById(ColorPickerConstants.DOM_ID);
     this.colorView = document.getElementById(ColorPickerConstants.COLOR_VIEW_ID);
     this.hexView = document.getElementById(ColorPickerConstants.HEX_VIEW_ID);
     this.shim = new iframeShim(this.pickerDiv);
     this.field = null;
     this.addedFields = {};
     var self = this;
     addEvent(document, "click", function () { self.hide(); }, false);
     addEvent(this.pickerDiv, "click", function (e) { ColorPicker.cancelHide(e); }, false);
}

ColorPicker.prototype.position = function () {
    // Get field's position relative to the offsetParent
    var x = 0;
    var y = 0;
    var elem = this.field;
    // TODO: RPC: Can this be done by getting absolute offset of the field and my element?
    while (elem != null && elem != this.pickerDiv.offsetParent) {
        x += elem.offsetLeft;
        y += elem.offsetTop;
        elem = elem.offsetParent;
    }

    // X - The default is to have the left match the field's left. If that won't work,
    // align the right sides.
    // Y - The default is to be flush with the bottom of the field. If that won't work,
    // place it flush with the top
    var pickerHeight = this.pickerDiv.offsetHeight;
    var pickerWidth = this.pickerDiv.offsetWidth;
    if (getObjX(this.field) + pickerWidth > getScrollX() + getWindowWidth()) {
        x -= pickerWidth - this.field.offsetWidth;
    }
    if (getObjY(this.field) + pickerHeight > getScrollY() + getWindowHeight()) {
        y -= pickerHeight;
    } else {
        y += this.field.offsetHeight;
    }

    this.shim.setStyle("left", x + "px");
    this.shim.setStyle("top", y + "px");
}

ColorPicker.prototype.hide = function () {
    this.shim.setStyle("display", "none");
}

ColorPicker.prototype.show = function (fieldId) {
    this.field = document.getElementById(fieldId);
    this.updateView(this.field.value);
    this.shim.setStyle("display", "block");
    if (!this.addedFields[fieldId]) {
        this.addedFields[fieldId] = true;
        var self = this;
        addEvent(this.field, "keydown", function (e) { self.handleKeyPress(e); }, false);
    }
    this.position();
}

ColorPicker.prototype.handleKeyPress = function(e) {
    var key = getEvent(e).keyCode;
    if (key == KEY_ESC) {
        this.hide();
    }
}

ColorPicker.prototype.selectBasic = function (value) {
    if (!this.field.disabled && this.field.value != value) {
        // Assign new value
        this.field.value = ColorPicker.formatHex(value);

        // Fire events
        if (this.field.fireEvent) {
            this.field.fireEvent('onchange');
        } else if (this.field.dispatchEvent) {
            var e = document.createEvent("HTMLEvents");
            e.initEvent('change', true, true);
            this.field.dispatchEvent(e);
        }
    }
    this.hide();
}

ColorPicker.prototype.updateView = function (hex) {
    var fHex = ColorPicker.formatHex(hex);
    this.colorView.style.backgroundColor = fHex;
    this.hexView.value = fHex;
}

// Lazily instantiated singleton
ColorPicker.singleton = null;

ColorPicker.cancelHide = function (e) {
    eventCancelBubble(e);
    return false;
}

ColorPicker.pick = function (fieldId, event) {
    if (!ColorPicker.singleton) {
        ColorPicker.singleton = new ColorPicker();
    }
    ColorPicker.singleton.show(fieldId);
    if (event) {
        ColorPicker.cancelHide(event);
    }
}

ColorPicker.formatHex = function (hex) {
    var newHex = ('#' == hex.charAt(0)) ? hex : '#' + hex;
    // Attempt to expand 3 hex to 6 hex
    if (newHex.match(/^#[0-9a-f]{3}$/i)) {
        var r = newHex.charAt(1);
        var g = newHex.charAt(2);
        var b = newHex.charAt(3);
        newHex = '#' + r + r + g + g + b + b;
    } else if (!newHex.match(/^#[0-9a-f]{6}$/i)) {
        newHex = '#FFFFFF';
    }
    return newHex;
}

ColorPicker.hiOn = function (elem, boxColor) {
    hiOn(elem);
    elem.style.backgroundColor = '#000000';
    ColorPicker.singleton.updateView(boxColor);
}

ColorPicker.hiOff = function (elem, boxColor) {
    hiOff(elem);
    elem.style.backgroundColor = ColorPicker.formatHex(boxColor);
}

function ScheduleReportOverlayUtil() {}

ScheduleReportOverlayUtil.displayScheduleReportDialogElement = function(id) {
	var dialog = OverlayDialogElement.getDialog('deleteScheduleReportDialog_' + id);
	dialog.isModal = true;
	dialog.setWidth(480);
	dialog.buttonContents = '<input value=\"' + LC.getLabel('Report', 'DeleteScheduleReportConfirm') + '\"' +
								' class=\"btn\" id=\"deleteScheduleReportDialog_' + id + '_overlayConfirmButton\"' +
								' name=\"overlayConfirmButton\"' +
								' onclick=\"if(true) {sfdcPage.getDialogById(\'deleteScheduleReportDialog_' + id + '\').hide();window.location.href=\'/' + id + '?delrep=1\';}\"' +
								' title=\"Yes, Delete Scheduled Report\" type=\"button\" />' +

							'<input value=\"Cancel\"' +
								' class=\"btn\" name=\"cancel\"' +
								' onclick=\"document.getElementById(\'del_' + id + '\').focus();OverlayDialogElement.getDialog(\'deleteScheduleReportDialog_' + id + '\').cancel()\"' +
								' title=\"Cancel\" type=\"button\" />';
	dialog.setTitle(LC.getLabel('Report', 'DeleteScheduleReportTitle'));
	var topContent = LC.getLabel('Report', 'DeleteScheduleReportContentTopHalf');
	var bottomContent = LC.getLabel('Report', 'DeleteScheduleReportContentBottom');
	dialog.contents = '<div><table ><tr><td><img src=\"/s.gif\" alt=\"Warning\"  class=\"warningLarge\" style=\'margin-right: 15px; margin-left: 8px\'=\"style=\'margin-right: 15px\'\" title=\"Warning\"/><\/td><td><br\/>' + topContent + '<br\/><br\/>' + bottomContent + '<\/td><\/tr>\n<\/table><\/div>';
	dialog.createContent();
	dialog.show();
	document.getElementById('deleteScheduleReportDialog_' + id + '_overlayConfirmButton').focus();
	return false;
}

/*
 * @author ldelascurain
 * @since 150
 *
 */

function FieldTree( rootList, formulaType, servletUrl ) {

    this.rootList = rootList;        //List of objects
    this.currentNode = FieldTree.ROOT_NODE;
    this.currentDepth = 0;
    this.formulaType = formulaType;    
    this.servletUrl = servletUrl;
}


FieldTree.LOADING_MARKER = "__";
FieldTree.ROOT_NODE = new Object();

FieldTree.prototype.getCurrentList = function() {
	if (this.currentNode === FieldTree.ROOT_NODE){
		return this.rootList; 
	} else {
	    return this.getChildren(this.currentNode);
	}
};

FieldTree.prototype.ascend = function(depthIn){

    var depth = depthIn ? depthIn : this.currentDepth - 1;
    if (depthIn === 0){
        depth = 0;
    }
    if (depth > this.currentDepth){
        depth = this.currentDepth;
    }

    while(this.currentDepth > depth){
         var parent = this.currentNode;
         if (!parent){
             return;
         }
         else if (!parent.parent) {
             this.currentNode = FieldTree.ROOT_NODE;
             this.currentDepth = 0;
         }
         else {
             this.currentNode = parent.parent;
             this.currentDepth--;
         }
    }
};

FieldTree.prototype.handleChildrenResponse = function(response, nodeToRefresh, onLazyLoad){
	var result = eval(Util.evalAjaxServletOutput(response.responseText)[AjaxGetFieldTreeChildren.NODE_LIST]);
	nodeToRefresh.setChildren(result);
	if (onLazyLoad){
		onLazyLoad(nodeToRefresh);
	}
};

FieldTree.prototype.handleChildrenError = function(response, nodeToRefresh, onLazyLoad){
	nodeToRefresh.setChildren([new FieldTreeNode(FieldTree.LOADING_MARKER, true, null, LC.getLabel("Global", "error"), true)]);
	if (onLazyLoad){
		onLazyLoad(nodeToRefresh);
	}
}

FieldTree.prototype.descend = function( selectedKey ) {
    var selectedNode = this.getNodeFromCurrentList( selectedKey );
    if (!selectedNode){
        return false;
    }
    if (selectedNode.isLeaf){
        return false;
    } 
    this.currentNode = selectedNode;
    this.currentDepth++;
    return true;
};

FieldTree.prototype.getChildren = function( selectedNode, onLazyLoad ){
	if (!selectedNode.isLeaf && !selectedNode.children){
		message = {};
		message[AjaxGetFieldTreeChildren.NODE_KEY] = selectedNode.getLabelToInsert(true);
		message[AjaxGetFieldTreeChildren.FORMULA_TYPE] = this.formulaType;
		var self = this;
		XBrowser.postHttpResponse(this.servletUrl, function(response) {self.handleChildrenResponse(response, selectedNode, onLazyLoad);}, 
			XBrowser.buildPost(message), function(response) {self.handleChildrenError(response, selectedNode, onLazyLoad);});
		selectedNode.setChildren([new FieldTreeNode(FieldTree.LOADING_MARKER, true, null, LC.getLabel("Global", "loading"), true)]);
	}
    return selectedNode.children;
};

FieldTree.prototype.getNodeFromCurrentList = function( selectedKey ) {
    var selectedNode;
    var currentList = this.getCurrentList();
    for(var i=0; i < currentList.length; i++){
        if (currentList[i].key == selectedKey ){
            selectedNode = currentList[i];
            break;
        }
    }
    return selectedNode;
};


var FilterEdit = function(){}

FilterEdit.prototype.disableDiv = function(divId,disableIt) {
    var obj = document.getElementById(divId)
    if (obj!=null) {
      obj.disabled = disableIt;
      obj.selectedIndex = obj.options.length - 1;
    }
}

// after server-side search, we set focus on the search element.
FilterEdit.prototype.setFocusOnSearch = function() {
    var els = document.getElementsByName(FilterEditPageConstants.pSEARCH_ANCHOR);
    if (els && els.length == 1){
        var anchor = els[0];
        anchor.focus();
    }
}
var SELECT_MENU_SELECT = 1;
var SELECT_MENU_SIDEWAYS = 2;

/**
 * A class that acts more or less exactly like a select box.
 *
 * @param sourceID The DOM id of a UL that will form the elements of the select
 * @param targetID A div target in which to build the SelectMenu
 * @param displayWord A string to display as the initial entry of the menu.
 * @param hasDefaultAction Splits the button in two parts if true: the button area, which when clicked
 *		  loads the first link in the list, and the arrow area, which displays or hides the menu.
 * @author emoses
 * @deprecated don't use this, use MenuButton instead
 */
function SelectMenu(sourceId, targetId, displayWord, selectMenuOuterClass, selectMenuClass, style, groupClass, needScrollbars, hasDefaultAction, isRightAligned){
    this.sourceList = document.getElementById(sourceId)
    this.select = null;
    this.menuDiv = null;
    this.displayWord = displayWord;
    this.targetDiv = document.getElementById(targetId)
    this.divClass = selectMenuOuterClass;
    this.menuClass = selectMenuClass;
    this.menuOpen = false;
    this.hasSetPosition = false;
    this.scrollbars = needScrollbars;
    this.hasDefaultAction = hasDefaultAction;
    this.isCreateNew = false;
    this.isRightAligned = isRightAligned;

    if (style){
        this.style = style;
    } else {
        this.style = SELECT_MENU_SELECT;
    }

    var self = this;

    this.documentHideMenu = function(e){
        var elem = getEventTarget(e);
        if(elem.className == groupClass) { return;}
        if (self.menuOpen){
            self.hideMenu();
        }
    }

    this.handleDocumentKeyDown = function(e){
        var evt = getEvent(e);

        if (self.menuOpen && evt.keyCode == KEY_ESC){
            //ESC key, when not pinned and all the way out
            self.hideMenu();
        }
    };

    this.handleDivClick = function(e) {
        var elem = getEventTarget(e);
        if(elem.className == groupClass) { return;}

        if (self.hasDefaultAction) {
            var nOffsetX=(e.layerX)?(e.layerX):e.offsetX;
            if(nOffsetX<(elem.offsetWidth-17)) {
                window.location = self.sourceList.childNodes[0].href;
                eventCancelBubble(e);
                return;
            }
        }
        if (self.menuOpen){
            self.hideMenu();

        } else {
            self.showMenu();
            self.setPosition();
        }
        eventCancelBubble(e);
    }

    if (!this.sourceList) return;
    if (!this.targetDiv) return;
    this.init();
}

SelectMenu.prototype.showMenu = function(){
    if (!this.isCreateNew) {
        this.targetDiv.style.position = "relative";
    }
    this.menuDiv.setStyle("display", "block");
    this.menuOpen = true;
};

SelectMenu.prototype.hideMenu = function(){
    if (!this.isCreateNew) {
        this.targetDiv.style.position = "static";
    }    
        this.menuDiv.setStyle("display", "none");
        this.menuOpen = false;
};

SelectMenu.prototype._setPositionSelect = function(){
    if (!this.hasSetPosition) {
        this.hasSetPosition = true;

        if (!this.isCreateNew) {
            this.menuDiv.setStyle("top", this.select.offsetHeight + "px");
            if(!this.isRightAligned){
                this.menuDiv.setStyle("left", "0px");
            }else{
                this.menuDiv.setStyle("right","3px");
            }
        }

        // Begin IE fix
        // Can't do this in CSS because the whitespace at the end of
        // the link elements don't function as a link.
        // So, grab the maximum text length of the link elements, make that
        // the width of the container div, and then set all link elements
        // to width 100%.

        var maxWidth = this.sourceList.childNodes[0].scrollWidth;
        var maxOptionWidth = maxWidth;
        for (var i = 1; i < this.sourceList.childNodes.length; i++) {
            if (this.sourceList.childNodes[i].scrollWidth > maxWidth)
                maxWidth = this.sourceList.childNodes[i].scrollWidth;
        }
        // this should not be set for menu with scrollbars
        for (var i = 0; i < this.sourceList.childNodes.length; i++) {
            this.sourceList.childNodes[i].style.width = "100%";
            if(this.sourceList.childNodes[i].offsetWidth > maxOptionWidth){
                maxOptionWidth = this.sourceList.childNodes[i].offsetWidth;
            }
        }
        this.menuDiv.setStyle("width", maxWidth + "px");
        // End IE Fix.

        // if the menu should have scrollbars then proceed with height calculations below
        if(this.scrollbars){
            // show a maximum of 20 items
            var maxHeight = this.sourceList.childNodes[0].offsetHeight*20;
            var actualHeight = this.sourceList.offsetHeight;
            if (actualHeight < maxHeight){
                maxHeight = actualHeight;
            }
            this.menuDiv.setStyle("height", maxHeight + "px");
            this.menuDiv.setStyle("overflowY", "auto");


        }
        if (this.menuDiv.div.offsetWidth < this.select.childNodes[0].offsetWidth){
            this.menuDiv.setStyle("width", this.select.childNodes[0].offsetWidth + "px");
            // firefox fix to ensure that horizontal scrollbar doesn't show up on click
            if(this.scrollbars){
                this.menuDiv.setStyle("width", (maxOptionWidth + 34) + "px");
                this.menuDiv.setStyle("backgroundColor", "#CCC");
                this.menuDiv.div.childNodes[0].style.width = this.menuDiv.div.offsetWidth - 34 + "px";
            }
        }
    }
};

SelectMenu.prototype._setPositionSideways = function() {
    this.menuDiv.setStyle("top", this.select.offsetHeight / 2 + "px");
    this.menuDiv.setStyle("left", this.select.offsetWidth + "px");
}

SelectMenu.prototype.init = function(){

    this.select = document.createElement("div");
    this.select.className = this.divClass;

    this.targetDiv.insertBefore(this.select, this.targetDiv.firstChild);

    var upperDiv = document.createElement("div");
    if (this.hasDefaultAction) {
        upperDiv.className = "selectMenuButton hasDefault";
    } else {
        upperDiv.className = "selectMenuButton";
    }
    this.select.appendChild(upperDiv);
    upperDiv.appendChild(document.createTextNode(this.displayWord));

    this.menuDiv = document.createElement("div");
    this.menuDiv.className = this.menuClass;
    this.select.appendChild(this.menuDiv);

    this.menuDiv.appendChild(this.sourceList);
    switch(this.style){
    case SELECT_MENU_SIDEWAYS:
        this.setPosition = this._setPositionSideways;
//      document.body.appendChild(this.menuDiv);
        break;
    case SELECT_MENU_SELECT:
    default:
        this.setPosition = this._setPositionSelect;
    }

    this.menuDiv = new iframeShim(this.menuDiv);
    this.menuDiv.setStyle("display", "none");
    this.menuDiv.setStyle("position", "absolute");

    addEvent(document, 'click', this.documentHideMenu, false);
    addEvent(document, 'keydown', this.handleDocumentKeyDown, true);
    addEvent(this.targetDiv, 'click', this.handleDivClick, false);
};

var UrlMap = new function(){
    this.urlMap = [];
    this.urlMap["EventTeamView"] = UserContext.getUrl("/appex/calendar/cal.jsp");
    this.urlMap["Login"] = UserContext.getUrl("/secur/login_page.jsp");
    this.urlMap["Home"] = UserContext.getUrl("/home/home.jsp");
    this.urlMap["Inviter"] = UserContext.getUrl("/email/inviter.jsp");
    this.urlMap["ComboBox"] = UserContext.getUrl("/widg/combobox.jsp");
    this.urlMap["EmailAuthorPopupCloser"] = UserContext.getUrl("/email/author/popupcloser.jsp");
    this.urlMap["BlankPage"] = UserContext.getUrl("/blank.html");

    this.getURL = function(key) {
        return this.urlMap[key];
    };

    // simple format of JSPDispatcher.getURL
    this.convertClassNameToUrl = function(className, qs) {
        var result = new String(UserContext.getUrl("/"));
        var classString = new String(className);

        // if this isn't in the standard package, the url needs to start with ui/general to signal that
        if (classString.indexOf(JSPDispatcher.STANDARD_PACKAGE + ".") != 0) {
            result = result.concat(JSPDispatcher.NONSTANDARD_PACKAGE_PREFIX);
        }
        // replace . with /
        result = result.concat(classString.replace(/\./g, '/'));
        if (qs != null) {
            result = result.concat(qs.toString());
        }
        return result.valueOf();
    }
}
/**
 * @author zzhou
 * since 148
 * AvailableSection fields javascript code; also see AvailableSection.js, CrtLayout.js, Lookups.js
 */

CrtLayoutElement.initAvailField = function(sectionId, fieldValue, fieldLabel, inLayout, isLookup) {
    var availField = new AvailableField(sectionId,fieldValue,fieldLabel, inLayout, isLookup);
    CrtLayoutElement.availableSections[sectionId].addField(availField);
}

function AvailableField(sectionId,fieldValue,fieldLabel, inLayout, isLookup) {
    this.id = fieldValue;
    this.sectionId = sectionId;
    this.fieldValue = fieldValue;
    this.fieldLabel = escapeHTML(fieldLabel);
    this.isSelected = false;
    this.pageNum = 1;
    this.inLayout = inLayout;
    this.isLookup = isLookup;
    //this takes too long to set for lookup fields -- set it when we actually hover
    this.displayName = this.isLookup ? null : this.fieldLabel;

    //TODO type
    this.type = 's';
    this.mousingOver = false;

}

AvailableField.prototype.getFieldValue = function() {
    return this.fieldValue;
}

AvailableField.prototype.render = function() {
    var className = 'availField';
    if (this.inLayout) {
        className += ' usedAvailField';
    } else {
        className += ' unusedAvailField';
    }
    if (this.isSelected) {
        className += ' ' +CrtLayoutElement.CSS_CLASS_SELECTED_ITEM;
    }
    if (!this.elem) {
        this.elem = document.getElementById(this.id);
    }
    if (this.elem) {
        this.elem.className = className;
    }

}

AvailableField.prototype.formatDName = function() {
    if (this.fieldLabel.length > CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH) {
        return this.fieldLabel.substring(0,CrtLayoutElement.MAX_DISPLAY_FIELD_LENGTH-2)+"...";
    }
    else {
        return this.fieldLabel;
    }
}

AvailableField.prototype.setToUsed = function() {
    var self = this;
    self.inLayout = true;
    if (this.mouseOverDiv) {
        this.mouseOverDiv.innerHTML = '';
        this.mouseOverDiv.style.display = 'none';
        this.mouseOverDiv = null;
        this.mousingOver = false;
    }
}

AvailableField.prototype.setToAvailable = function() {
    this.inLayout = false;
}

AvailableField.prototype.handleMouseOver = function(evt) {
    var evt = getEvent(evt);
    this.posX = getMouseX(evt);
    this.posY = getMouseY(evt);
    if (!this.inLayout && !CrtLayoutElement.dragMove && !this.mousingOver) {
        var self = this;
        this.timeOut = setTimeout(function() {self.setupMouseOverDiv();},CrtLayoutElement.HOVER_TIME_OUT)
        this.mousingOver = true;
    }
}

AvailableField.prototype.handleMouseOut = function (evt) {
    if (this.inLayout) {
        return;
    }
    document.getElementById(CrtLayoutElement.HOVER_DIV).style.display = 'none';
    clearTimeout(this.timeOut);
    this.mousingOver = false;
}

AvailableField.prototype.handleMouseDown = function(evt) {
      if (this.inLayout) {
          CrtLayoutElement.clearTextSelection();
          return;
      }
      var evt = getEvent(evt);
      if (!evt.shiftKey && !evt.ctrlKey && !this.isSelected) {
          this.toggleSelected(false);
      }
      CrtLayoutElement.mouseDown = true;
}

AvailableField.prototype.handleMouseClick = function(evt) {
    if (this.inLayout) {
        CrtLayoutElement.clearTextSelection();
        return;
    }
    var evt = getEvent(evt);
    if (evt.ctrlKey) {
        this.toggleSelected(true);
    } else {

    }
}

AvailableField.prototype.toggleSelected = function(isCtrlSelect) {
        if (this.isSelected) {
            this.removeSelection(false);
        }
        else {
            if (!isCtrlSelect) {
                MoveableItem.clearSelectedItems();
            }
            this.addSelection();
        }
}

//remove this field from the layout; used currently by the lookup sections
AvailableField.prototype.removeFromLayout = function() {
    if (this.inLayout) {
        var itemObj = CrtLayoutElement.lookupItemPosMap[this.fieldValue];
        //set this cell to empty and return the id of the table to reformat
        itemObj.handleMoved();
    }
}

AvailableField.prototype.removeSelection = function(noBucketRemove) {
    if (!noBucketRemove) {
        this.moveableItem.removeSelection();
    }
    this.moveableItem = null;
    this.removeSelectionFormatting();
}

AvailableField.prototype.removeSelectionFormatting = function() {
    this.isSelected = false;
    this.render();
}

AvailableField.prototype.handleMoved = function() {
    this.setToUsed();
    this.removeSelectionFormatting();
}

AvailableField.prototype.addSelection = function() {
    var addSelection;
    this.moveableItem = this.createMoveableItem();
    addSelection = this.moveableItem.addSelection();
    //are we mixing the selection Bucket?
    if (addSelection) {
        this.addSelectionFormatting();
    }
}

AvailableField.prototype.createMoveableItem = function() {
    return new MoveableItem(this.fieldValue,this.fieldLabel,this.displayName, null, this.type, this, false, false, this.isLookup, false);
}

AvailableField.prototype.addSelectionFormatting = function() {
    this.isSelected = true;
    this.render();
}

AvailableField.prototype.handleMoveTo = function() {
    this.setToAvailable();
    this.render();
}

AvailableField.prototype.setupMouseOverDiv = function(evt) {
    var moElem = document.getElementById(CrtLayoutElement.HOVER_DIV);
    var html = '';
    var posx = this.posX-210;
    var posy = this.posY-80;
    html += '<div class="mouseOverHeader">'+ this.fieldLabel + (this.isLookup ? ' ' + LC.getLabel("CRTLookupLayer","viaLookupParen") : '') + '</div>';
    if (!this.displayName) {
        this.displayName = CrtLayoutElement.getDisplayPath(this.fieldValue,true);
    }
    html += '<div class="mouseOverBody">'+LC.getLabel("CrtLayout","CustomLabel")+': '+ this.displayName + '<br>';
    if (this.isLookup) {
        html += '<br>';
        html += LC.getLabel("CrtLayout","lookupPath") + ' ' + CrtLayoutElement.getDisplayPath(this.fieldValue,false);
        html += '<br>';
    }
    html += '<br>' + LC.getLabel("CrtLayout","availFieldHover");
    moElem.innerHTML = html;
    moElem.style.display = 'block';
    moElem.style.left = posx+"px";
    moElem.style.top = posy+"px";
    return moElem;
}


/**
 * Preference bit vectors in js, stores index, name, and current value. Setting a preference
 * to a different value will automatically make an asynchronous request to save the value to the
 * db. Since only a few preferences are accessible/settable through javascript there's no need to
 * compress them into bit vectors. This only handles boolean preferences right now.
 * 
 * @author jmooney
 * @since 150
 */
function PreferenceBits(/* array of {index, name, value} */ preferences) {
    this.bitsByName = {};
    for (var i = 0; i < preferences.length; i++) {
        var pref = preferences[i];
        this.bitsByName[pref.name] = {index: pref.index, val: pref.value };
    }
}

PreferenceBits.prototype.getBoolean = function(/* string */ name) {
    return this.bitsByName[name].val;
}

PreferenceBits.prototype.getIndexByName = function(/* string */ name) {
    return this.bitsByName[name].index;
}

PreferenceBits.prototype.setBoolean = function(/* string */ name, /* boolean */ val) {
    if (typeof val == "boolean") {
        var current = this.bitsByName[name];
        if (current && current.val != val) {
            this.bitsByName[name].val = val;
            this.save(name);
        }
    }
}

PreferenceBits.prototype.save = function(name) {
    var pref = this.bitsByName[name];
    if (pref) {
        // don't care about the response
        XBrowser.postHttpResponse(UserContext.getUrl("/_ui/common/request/servlet/PreferenceServlet"),
                                  function(response) {},
                                  XBrowser.buildPost({val: pref.val, bit: pref.index}));
    }
}

/*
 * @author ldelascurain
 * @since 150
 *
 */

function FieldTreeController( container, rootNodeList, elementName, insertCurlyBangDelims, afterInsertCallback, formulaType, servletUrl){

    this.tree = new FieldTree( rootNodeList, formulaType, servletUrl);
    this.selects = [document.getElementById(FieldTreeConstants.SELECT_ID + "0")];
    this.elementName = elementName;
    this.insertCurlyBangDelims = insertCurlyBangDelims;
    this.container = container;
    this.afterInsertCallback = afterInsertCallback;
    
    var depthRE = /(\d+)$/;

    var self = this;

    this.handleSelectClick = function(e){
        var target = getEventTarget(getEvent(e));
        var match = depthRE.exec(target.name);
        if (!match){
            return;
        }
        var selectDepth = parseInt(match[1]);
        var selectedKey = target.options[target.selectedIndex].value;

        self.moveSelectionTo(selectDepth, selectedKey);
    }

    addEvent(this.container.firstChild.firstChild, 'change', this.handleSelectClick, false);
    this.hideSelects();
};

FieldTreeController.prototype.setScrollDiv = function(div){
	this.scrollDiv = div;
};

FieldTreeController.prototype.ajaxRefreshNode = function(refreshedNode){
	if (refreshedNode === this.tree.currentNode){
		this.eraseSelects(this.tree.currentDepth);
		this.buildSelect(refreshedNode.children, this.tree.currentDepth);
		this.scrollRight();
	}
};

FieldTreeController.prototype.moveSelectionTo = function(selectDepth, selectedKey){
    //TODO:  fix for change to "none"
    if (!selectedKey){
        return;
    }

    if (selectDepth < this.tree.currentDepth){
        this.tree.ascend(selectDepth);
    }

    var selectedNode = this.tree.getNodeFromCurrentList(selectedKey);

    if (!(selectedNode.isLeaf)){
    	var self = this;
        this.buildSelect(this.tree.getChildren(selectedNode, function(refreshedNode) {self.ajaxRefreshNode(refreshedNode);}), selectDepth + 1);
        this.tree.descend(selectedNode.key);
   	    this.scrollRight();
    }
    else {
        // Add the Insert code
        var insertString = selectedNode.getLabelToInsert();
        var extraAttributes = selectedNode.getExtraAttributes();
        this.buildInsert(insertString, selectDepth + 1, extraAttributes);
   	    this.scrollRight();
    }
}

FieldTreeController.prototype.focusTop = function(){
    var topSelect = this.selects[0];
    if(topSelect){
        topSelect.focus();
    }
}

FieldTreeController.prototype.reset = function(){
    this.tree.ascend(0);
    this.selects = [document.getElementById(FieldTreeConstants.SELECT_ID + "0")];

    var topSelect = this.selects[0];
    if (topSelect.options.length > 0){
        topSelect.selectedIndex = 0;
        this.moveSelectionTo(0, topSelect.options[0].value);
    }
}

FieldTreeController.prototype.buildSelect = function( nodeList, index ){

    var map = [];
    for(var i=0;i<nodeList.length;i++){
        var nodeLabel = nodeList[i].isLeaf ? nodeList[i].labelName : (nodeList[i].labelName + " &gt;");
        map[i] = [nodeLabel, nodeList[i].key];
    }

    this.eraseSelects(index);

    var attributeMap = {"size":"9", "name":FieldTreeConstants.SELECT_ID + this.selects.length, "class":"fieldTreeSelect"};
    var selectHTML = Util.createDynamicSelect(attributeMap, map, false);

    var wrapper = document.createElement("TD");
    wrapper.id = "selectWrapper" + this.selects.length;
    wrapper.className = "selectWrapper";
    this.container.appendChild(wrapper);
    wrapper.innerHTML = selectHTML;
    wrapper.isDynamicSelect = true;
    this.selects.push(wrapper.firstChild);


    addEvent(this.selects[index], 'change', this.handleSelectClick, false);
}

FieldTreeController.prototype.buildInsert = function( insertString, index, extraAttributes ){
    var insertInfoHTML = LC.getLabel("NewFormulaEditor", "SelectedInfo");
    var insertText = LC.getLabel("Buttons", "ins");
    var insertStringHTML = insertString;
    var insertButtonHTML = "<input type='button' id='fieldInsertButton' name='insertButton' class='btn' value='" + insertText + "' />";
    var self = this;

    if (this.selects[index]) {
        this.eraseSelects(index);
    }
    var insertBox = document.createElement("TD");
    this.container.appendChild(insertBox);
    insertBox.id = "insertBox";

    var wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperInfo" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertInfoHTML;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperInfo";

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperString" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertStringHTML;
    wrapper.isDynamicSelect = true;
    wrapper.className = "insertWrapperString";

    this.selects.push(wrapper.firstChild);

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperAttributes" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = extraAttributes;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperAttributes";

    wrapper = document.createElement("SPAN");
    wrapper.id = "insertWrapperButton" + this.selects.length;
    insertBox.appendChild(wrapper);
    wrapper.innerHTML = insertButtonHTML;
    wrapper.isDynamicSelect = false;
    wrapper.className = "insertWrapperButton";

    addEvent(document.getElementById("fieldInsertButton"), "click", function(){self.insertCode(self.elementName, insertString, self.insertCurlyBangDelims);}, false);

}

FieldTreeController.prototype.eraseSelects = function(index){
    var i = this.selects.length;
    while (i > index ){
        i--;
        var element = this.selects[i].parentNode;
        while (element.nodeName != "TD"){
            element = element.parentNode;
        }
        this.container.removeChild(element);
        this.selects.pop();
    }
}

FieldTreeController.prototype.insertCode = function(elementName, insertString, insertCurlyBangDelims){
    FormulaEditor.insertCode( elementName, insertString, insertCurlyBangDelims);
    if (this.afterInsertCallback){
        this.afterInsertCallback();
    }
}

FieldTreeController.prototype.scrollRight = function(){
	var container = this.scrollDiv || this.container;
	if (container.clientWidth == 0){
		//IE fix
		container = container.parentNode;
	}
    container.scrollLeft = container.scrollWidth - container.clientWidth;
}

FieldTreeController.prototype.showSelects = function(){
    for (var i=0; i< this.selects.length; i++ ){
        this.selects[i].style.display = "inline";
    }
}

FieldTreeController.prototype.hideSelects = function(){
    for (var i=0; i< this.selects.length; i++ ){
        var element = this.selects[i];
        if (element!=null && element.nodeName == "SELECT"){
            element.style.display = "none";
        }
    }
}

// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
// ===================================================================

// HISTORY
// ------------------------------------------------------------------
// May 17, 2003: Fixed bug in parseDate() for dates <1970
// March 11, 2003: Added parseDate() function
// March 11, 2003: Added "NNN" formatting option. Doesn't match up
//                 perfectly with SimpleDateFormat formats, but 
//                 backwards-compatability was required.

// ------------------------------------------------------------------
// These functions use the same 'format' strings as the 
// java.text.SimpleDateFormat class, with minor exceptions.
// The format string consists of the following abbreviations:
// 
// Field        | Full Form          | Short Form
// -------------+--------------------+-----------------------
// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
// Month        | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
//              | NNN (abbr.)        |
// Day of Month | dd (2 digits)      | d (1 or 2 digits)
// Day of Week  | EE (name)          | E (abbr)
// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
// Hour (0-11)  | KK (2 digits)      | K (1 or 2 digits)
// Hour (1-24)  | kk (2 digits)      | k (1 or 2 digits)
// Minute       | mm (2 digits)      | m (1 or 2 digits)
// Second       | ss (2 digits)      | s (1 or 2 digits)
// AM/PM        | a                  |
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
//  "MMM d, y" matches: January 01, 2000
//                      Dec 1, 1900
//                      Nov 20, 00
//  "M/d/yy"   matches: 01/20/00
//                      9/2/00
//  "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------

function DateUtil() {}

DateUtil.MONTH_NAMES = new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
DateUtil.DAY_NAMES = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');

DateUtil.LZ = function(x) {return(x<0||x>9?"":"0")+x}

// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
DateUtil.isDate = function(val,format) {
    var date=DateUtil.getDateFromFormat(val,format);
    if (date==0) { return false; }
    return true;
    }

// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
//   Compare two date strings to see which is greater.
//   Returns:
//   1 if date1 is greater than date2
//   0 if date2 is greater than date1 of if they are the same
//  -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
DateUtil.compareDates = function(date1,dateformat1,date2,dateformat2) {
    var d1=DateUtil.getDateFromFormat(date1,dateformat1);
    var d2=DateUtil.getDateFromFormat(date2,dateformat2);
    if (d1==0 || d2==0) {
        return -1;
        }
    else if (d1 > d2) {
        return 1;
        }
    return 0;
    }

// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
DateUtil.formatDate = function(date,format) {
    format=format+"";
    var result="";
    var i_format=0;
    var c="";
    var token="";
    var y=date.getYear()+"";
    var M=date.getMonth()+1;
    var d=date.getDate();
    var E=date.getDay();
    var H=date.getHours();
    var m=date.getMinutes();
    var s=date.getSeconds();
    var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
    // Convert real date parts into formatted versions
    var value=new Object();
    if (y.length < 4) {y=""+(y-0+1900);}
    value["y"]=""+y;
    value["yyyy"]=y;
    value["yy"]=y.substring(2,4);
    value["M"]=M;
    value["MM"]=DateUtil.LZ(M);
    value["MMM"]=DateUtil.MONTH_NAMES[M-1];
    value["NNN"]=DateUtil.MONTH_NAMES[M+11];
    value["d"]=d;
    value["dd"]=DateUtil.LZ(d);
    value["E"]=DateUtil.DAY_NAMES[E+7];
    value["EE"]=DateUtil.DAY_NAMES[E];
    value["H"]=H;
    value["HH"]=DateUtil.LZ(H);
    if (H==0){value["h"]=12;}
    else if (H>12){value["h"]=H-12;}
    else {value["h"]=H;}
    value["hh"]=DateUtil.LZ(value["h"]);
    if (H>11){value["K"]=H-12;} else {value["K"]=H;}
    value["k"]=H+1;
    value["KK"]=DateUtil.LZ(value["K"]);
    value["kk"]=DateUtil.LZ(value["k"]);
    if (H > 11) { 
        value["a"] = DateUtil.getPMSymbol();
    } else {
        value["a"] = DateUtil.getAMSymbol();
    }
    value["m"]=m;
    value["mm"]=DateUtil.LZ(m);
    value["s"]=s;
    value["ss"]=DateUtil.LZ(s);
    while (i_format < format.length) {
        c=format.charAt(i_format);
        token="";
        while ((format.charAt(i_format)==c) && (i_format < format.length)) {
            token += format.charAt(i_format++);
            }
        if (value[token] != null) { result=result + value[token]; }
        else { result=result + token; }
        }
    return result;
    }
    
// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
DateUtil._isInteger = function(val) {
    var digits="1234567890";
    for (var i=0; i < val.length; i++) {
        if (digits.indexOf(val.charAt(i))==-1) { return false; }
        }
    return true;
    }
DateUtil._getInt = function(str,i,minlength,maxlength) {
    for (var x=maxlength; x>=minlength; x--) {
        var token=str.substring(i,i+x);
        if (token.length < minlength) { return null; }
        if (DateUtil._isInteger(token)) { return token; }
        }
    return null;
    }
    
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the 
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
DateUtil.getDateFromFormat = function(val,format) {
    val=val+"";
    format=format+"";
    var i_val=0;
    var i_format=0;
    var c="";
    var token="";
    var token2="";
    var x,y;
    var now=new Date();
    var year=now.getYear();
    var month=now.getMonth()+1;
    var date=1;
    var hh=now.getHours();
    var mm=now.getMinutes();
    var ss=now.getSeconds();
    var ampm="";
    
    while (i_format < format.length) {
        // Get next token from format string
        c=format.charAt(i_format);
        token="";
        while ((format.charAt(i_format)==c) && (i_format < format.length)) {
            token += format.charAt(i_format++);
            }
        // Extract contents of value based on format token
        if (token=="yyyy" || token=="yy" || token=="y") {
            if (token=="yyyy") { x=2;y=4; } // x=2,y=4 to be consistent with java.
            if (token=="yy")   { x=2;y=2; }
            if (token=="y")    { x=2;y=4; }
            year=DateUtil._getInt(val,i_val,x,y);
            if (year==null) { return 0; }
            i_val += year.length;
            if (year.length==2) {
                if (year > 70) { year=1900+(year-0); }
                else { year=2000+(year-0); }
                }
            }
        else if (token=="MMM"||token=="NNN"){
            month=0;
            for (var i=0; i<DateUtil.MONTH_NAMES.length; i++) {
                var month_name=DateUtil.MONTH_NAMES[i];
                if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
                    if (token=="MMM"||(token=="NNN"&&i>11)) {
                        month=i+1;
                        if (month>12) { month -= 12; }
                        i_val += month_name.length;
                        break;
                        }
                    }
                }
            if ((month < 1)||(month>12)){return 0;}
            }
        else if (token=="EE"||token=="E"){
            for (var i=0; i<DateUtil.DAY_NAMES.length; i++) {
                var day_name=DateUtil.DAY_NAMES[i];
                if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
                    i_val += day_name.length;
                    break;
                    }
                }
            }
        else if (token=="MM"||token=="M") {
            month=DateUtil._getInt(val,i_val,1,2); // Always use min len 1 to be lenient.
            if(month==null||(month<1)||(month>12)){return 0;}
            i_val+=month.length;}
        else if (token=="dd"||token=="d") {
            date=DateUtil._getInt(val,i_val,1,2); // Always use min len 1 to be lenient.
            if(date==null||(date<1)||(date>31)){return 0;}
            i_val+=date.length;}
        else if (token=="hh"||token=="h") {
            hh=DateUtil._getInt(val,i_val,token.length,2);
            if(hh==null||(hh<1)||(hh>12)){return 0;}
            i_val+=hh.length;}
        else if (token=="HH"||token=="H") {
            hh=DateUtil._getInt(val,i_val,token.length,2);
            if(hh==null||(hh<0)||(hh>23)){return 0;}
            i_val+=hh.length;}
        else if (token=="KK"||token=="K") {
            hh=DateUtil._getInt(val,i_val,token.length,2);
            if(hh==null||(hh<0)||(hh>11)){return 0;}
            i_val+=hh.length;}
        else if (token=="kk"||token=="k") {
            hh=DateUtil._getInt(val,i_val,token.length,2);
            if(hh==null||(hh<1)||(hh>24)){return 0;}
            i_val+=hh.length;hh--;}
        else if (token=="mm"||token=="m") {
            mm=DateUtil._getInt(val,i_val,token.length,2);
            if(mm==null||(mm<0)||(mm>59)){return 0;}
            i_val+=mm.length;}
        else if (token=="ss"||token=="s") {
            ss=DateUtil._getInt(val,i_val,token.length,2);
            if(ss==null||(ss<0)||(ss>59)){return 0;}
            i_val+=ss.length;}
        else if (token=="a") {
            var am = DateUtil.getAMSymbol();
            var pm = DateUtil.getPMSymbol();
            var stra = val.substring(i_val, i_val + am.length);
            var strp = val.substring(i_val, i_val + pm.length);
            if (stra == am || stra.toUpperCase() == am) {
                ampm = am;
            } else if (strp == pm || strp.toUpperCase() == pm) {
                ampm = pm;
            } else {
                return 0;
            }
                i_val += ampm.length;
        }
        else {
            if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
            else {i_val+=token.length;}
            }
        }
    // If there are any trailing characters left in the value, it doesn't match
    if (i_val != val.length) { return 0; }
    // Is date valid for month?
    if (month==2) {
        // Check for leap year
        if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
            if (date > 29){ return 0; }
            }
        else { if (date > 28) { return 0; } }
        }
    if ((month==4)||(month==6)||(month==9)||(month==11)) {
        if (date > 30) { return 0; }
        }
    // Correct hours value
    if (hh<12 && ampm == DateUtil.getPMSymbol()) { hh=hh-0+12; }
    else if (hh>11 && ampm == DateUtil.getAMSymbol()) { hh-=12; }
    var newdate=new Date(year,month-1,date,hh,mm,ss);
    return newdate.getTime();
    }

// ------------------------------------------------------------------
// parseDate( date_string [, prefer_euro_format] )
//
// This function takes a date string and tries to match it to a
// number of possible date formats to get the value. It will try to
// match against the following international formats, in this order:
// y-M-d   MMM d, y   MMM d,y   y-MMM-d   d-MMM-y  MMM d
// M/d/y   M-d-y      M.d.y     MMM-d     M/d      M-d
// d/M/y   d-M-y      d.M.y     d-MMM     d/M      d-M
// A second argument may be passed to instruct the method to search
// for formats like d/M/y (european format) before M/d/y (American).
// Returns a Date object or null if no patterns match.
// ------------------------------------------------------------------
DateUtil.parseDate = function(val) {
    var preferEuro=(arguments.length==2)?arguments[1]:false;
    generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
    monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d','M.d');
    dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M','d.M');
    var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
    var d=null;
    for (var i=0; i<checkList.length; i++) {
        var l=window[checkList[i]];
        for (var j=0; j<l.length; j++) {
            d=DateUtil.getDateFromFormat(val,l[j]);
            if (d!=0) { return new Date(d); }
            }
        }
    return null;
}

DateUtil.TIMEZONES;

DateUtil.getTimezoneOffset = function(){

    var browserDate = new Date();
    var browserOffsetFromGMT = browserDate.getTimezoneOffset() * (60 * 1000);

    var index = DateUtil.getTimezoneIndex(browserDate);
    if (DateUtil.TIMEZONES == undefined){
        DateUtil.TIMEZONES = DateUtil.getTimezones(browserDate);
    }
    var sfdcOffsetFromGMT = DateUtil.TIMEZONES[index];

    // alert(browserOffsetFromGMT + " " + sfdcOffsetFromGMT + " " + index + " " + browserDate + "\n\n");
    // listProperties(timezones);
    
    var offset = sfdcOffsetFromGMT + browserOffsetFromGMT;
    
    return offset;

}

// Returns true if browser timezone matches system timezone
DateUtil.isBrowserAndSystemTimezoneSame = function(){
    var offset = DateUtil.getTimezoneOffset();
    return offset == 0;
}

DateUtil.getTimezoneIndex = function(date){
    return DateUtil.formatDate(date, "yyyyMMdd");
}

DateUtil.getTimezones = function(date){

    var qs = new QueryString("");
    qs.add("ts", date.getTime());
    var url = UserContext.getUrl("/home/timezones.jsp") + qs.toString();
    
    var tz = null;
    
    var text = DesktopAjax.prototype.doGet(url);
    if (text){
        text = trim(text);
        var local = eval('(' + text + ')');
        return local;
        if (local){
            tz = local;
        }
    } 
    
    return tz;
}

DateUtil.rollDate = function(day, numDays){
    var newDate = new Date(day.getTime());
    newDate.setDate(newDate.getDate() + numDays);
    return newDate;
}

DateUtil.roundDate = function(date){
    var newDate = new Date(date.getTime());
    newDate.setHours(0);
    newDate.setMinutes(0);
    newDate.setSeconds(0);
    return newDate;
}

/*
 * Rest of file added by SFDC.
 */

/**
 * parse a date into a string using the user locale date format
 */
DateUtil.getDateStringFromUserLocale = function(date) {
    return DateUtil.formatDate(date, UserContext.dateFormat);
}

/**
 * parse a string using the user locale date format into a javascript Date object
 */
DateUtil.getDateFromUserLocale = function(str) {
    return new Date(DateUtil.getDateFromFormat(str, UserContext.dateFormat));
}

/**
 * parse a date into a string that includes time using the user locale date time format
 */
DateUtil.getDateTimeStringFromUserLocale = function(date) {
    return DateUtil.formatDate(date, UserContext.dateTimeFormat);
}

/**
 * parse a string with time using the user locale date time format into a javascript Date object
 */
DateUtil.getDateTimeFromUserLocale = function(str) {
    return new Date(DateUtil.getDateFromFormat(str, UserContext.dateTimeFormat));
}

DateUtil.getAMSymbol = function() {
    if (UserContext.initialized) {
        return UserContext.ampm[0];
    } else {
        return "AM";
    }
}

DateUtil.getPMSymbol = function() {
    if (UserContext.initialized) {
        return UserContext.ampm[1];
    } else {
        return "PM";
    }
}

/**
 * Java style date comparisons. Compares by day, month, and year only.
 */
DateUtil.equals = function(date1, date2) {
    return date1 && date2 && DateUtil.compare(date1, date2) == 0;
}

DateUtil.lessThan = function(date1, date2) {
    return DateUtil.compare(date1, date2) < 0;
}

DateUtil.greaterThan = function(date1, date2) {
    return DateUtil.compare(date1, date2) > 0;
}

DateUtil.compare = function(date1, date2) {
    if (date1.getFullYear() != date2.getFullYear()) {
        return date1.getFullYear() - date2.getFullYear();
    } else {
        if (date1.getMonth() != date2.getMonth()) {
            return date1.getMonth() - date2.getMonth();
        } else {
            return date1.getDate() - date2.getDate();
        }
    }
}

// possible date separators, should just match the user's format separator
DateUtil.separators = ['/', '-', '.'];
/**
 * Checks if a year was input (if not, inserts current year) and allows for
 * 2-digit year inputs. Then calls evaluateShortcut() to evaluate date picker
 * shortcuts like "today". Currently only for en_US users.
 */
DateUtil.checkYear = function(field, callOnChange) {
    var val = field.value.toLowerCase();
    if (val && val.length > 0) {
        var date = DateUtil.getDateTimeFromUserLocale(UserContext.today);
    }
    // figure out what separator they're using
    var separator = null;
    for (var i = 0; i < DateUtil.separators.length; i++) {
        if (val.indexOf(DateUtil.separators[i]) != -1) {
            separator = DateUtil.separators[i];
            break;
        }
    }
    var setField = false;
    
    if (separator) {
        // set the date to the 1st to avoid month wrapping
        date.setDate(1);
        var nums = val.split(separator);
        // see if they left off the year (only in locales where year is last)
        if (nums.length == 2) {
            // set month and date (year was already set to today's year)
            if (!isNaN(nums[0]) && !isNaN(parseInt(nums[1], 10))) {
                date.setMonth(parseInt(nums[0], 10) - 1);
                date.setDate(parseInt(nums[1], 10));
                setField = true;
            }
        } else if (nums.length == 3) {
            // fix the year if necessary
            if (!isNaN(parseInt(nums[2], 10)) && !isNaN(nums[0]) && !isNaN(nums[1])) {
                var year = parseInt(nums[2], 10);
                //allow 2 digit year, but still check the separator
                if (year / 1000 < 1) {
                    date.setMonth(parseInt(nums[0], 10) - 1);
                    date.setDate(parseInt(nums[1], 10));
                    // anything under 60 is in 2000, [60-99] is 1900
                    if (year >= 60 && year < 100) {
                        date.setFullYear(year + 1900);
                    } else {
                        date.setFullYear(year + 2000);
                    }
                    setField = true;
                } else if (separator != '/') {
                    field.value = nums[0] + "/" + nums[1] + "/" + nums[2];
                    if (callOnChange && field.onchange) {
                        field.onchange();
                    }
                    return;
                }
            }
        }
    } else {
        DateUtil.evaluateShortcut(field, callOnChange);
    }

    if (setField) {
          field.value = DateUtil.getDateStringFromUserLocale(date);
        if (callOnChange && field.onchange) {
            field.onchange();
        }
    }
}

// need to localize later
DateUtil.DAY_SHORTCUTS = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];

/**
 * Attempts to take a shortcut and turn it into a valid date, i.e. if the user
 * enters "today", this will replace it with today's date. Currently only for
 * English language users (because the shortcuts are in English).
 */
DateUtil.evaluateShortcut = function(field, callOnChange) {
     var setField = false;
    var val = field.value.toLowerCase();
    if (val && val.length > 0) {
        var date = DateUtil.getDateTimeFromUserLocale(UserContext.today);
    }

    if (val.indexOf("tod") == 0) {
        setField = true;
    } else if (val.indexOf("yes") == 0) {
        date.setDate(date.getDate() - 1);
        setField = true;
    } else if (val.indexOf("tom") == 0) {
        date.setDate(date.getDate() + 1);
        setField = true;
    } else if (val.length >= 3) {
        for (var i = 0; i < DateUtil.DAY_SHORTCUTS.length; i++) {
            if (val.indexOf(DateUtil.DAY_SHORTCUTS[i].toLowerCase()) == 0) {
                var dif = i - date.getDay();
                if (dif < 0) {
                    dif += 7;
                }
                date.setDate(date.getDate() + dif);
                setField = true;
                break;
            }
        }
    }
    if (setField) {
        field.value = DateUtil.getDateStringFromUserLocale(date);
        if (callOnChange && field.onchange) {
            field.onchange();
        }
    }
}

DateUtil.differenceInMinutes = function (date1, date2) {
    var diffInMillis = date2.getTime() - date1.getTime();
    return Math.round(diffInMillis / (60 * 1000))
}

DateUtil.getDateFromValue = function (fieldValue, hasTime) {
    var time = hasTime ? DateUtil.getDateFromFormat(fieldValue, UserContext.dateTimeFormat) :
                         DateUtil.getDateFromFormat(fieldValue, UserContext.dateFormat);
    if (time != 0) {
        return new Date(time);
    }
    return null;
}
function FormulaEditor(){};

FormulaEditor.init = function( editorElementId, functionSelectionElementId, formId, validationStatusNotValidated ) {
    FormulaEditor.editorElementId = editorElementId;
    FormulaEditor.functionSelectionElementId = functionSelectionElementId;
    FormulaEditor.formId = formId;
    FormulaEditor.validationStatusNotValidated = validationStatusNotValidated;
    FormulaEditor.setFunctionInfo(FormulaEditor.getSelectedFunction());

}

FormulaEditor.setFunctionInfo = function( functionName ) {
    if (!functionName)
        return;
    document.getElementById('funcFormat').innerHTML = functionNameToPrototypeMap[functionName];
    document.getElementById('funcExplain').innerHTML = functionNameToDescriptionMap[functionName];
}

FormulaEditor.getSelectedFunction = function() {
    functionSelectElement = document.getElementById(FormulaEditor.functionSelectionElementId);
    if (!functionSelectElement)
        return null;

    return functionSelectElement.options[functionSelectElement.selectedIndex].value;
}

FormulaEditor.setListToCategory = function( category, categoryMap, targetId, defaultCategory, preserveFirstOption) {
    var targetSelectElement = document.getElementById(targetId);
    var list = categoryMap[(category != '') ? category : defaultCategory];
    var offset = (preserveFirstOption) ? 1 : 0;

    targetSelectElement.options.length = offset;
    if (!list) return;
    for (var i = 0; i < list.length; i++) {
        targetSelectElement.options[i + offset] = list[i];
    }
}

FormulaEditor.switchMode = function( mode ) {
    if (document.getElementById('editorMode').value == mode)
        return;
    document.getElementById('editorMode').value = mode;
    document.getElementById('changeEditorMode').value = "1";
    document.getElementById(FormulaEditor.formId).submit();
}

FormulaEditor.formulaKeypressEventListener = function() {
    var validationStatus = document.getElementById('validationStatus');
    if(validationStatus) {
        validationStatus.innerHTML = FormulaEditor.validationStatusNotValidated;
    }
}

FormulaEditor.registerFormulaEventListeners = function( name ) {
    // Wire up event listener to change validation status
    setCurrentParamName(name);
    var editorDoc = getDoc();
    if (editorDoc.addEventListener)
        editorDoc.addEventListener("keypress", FormulaEditor.formulaKeypressEventListener, false);
    else
        editorDoc.onkeypress = FormulaEditor.formulaKeypressEventListener;
}

FormulaEditor.insertFieldReference = function( name, fieldSelector, insertCurlyBangDelims ) {
    var value = fieldSelector.options[fieldSelector.selectedIndex].value;
    if (value) {
        FormulaEditor.insertCode(name, value, insertCurlyBangDelims);
        fieldSelector.selectedIndex = 0;
    }
}

FormulaEditor.insertCode = function( name, value, insertCurlyBangDelims ) {
    var insert;
    restoreSelection(document.getElementById(name));
    insert = (insertCurlyBangDelims && !findDelimiters(name, '{!', '}')) ? '{!' + value + '}' : ' ' + value + ' ';
    insertTextAtSelectionInEditor(name, insert);
}

/*
 * History Storage for ajax based states
 */
/** 
   Material Copyrighted  2005, Brad Neuberg, bkn3@columbia.edu  
   Modified by salesforce.com 2007
   --------------------------------STARTS HERE-----------------------------------------

   Copyright (c) 2005, Brad Neuberg, bkn3@columbia.edu
   http://codinginparadise.org
   
   Permission is hereby granted, free of charge, to any person obtaining 
   a copy of this software and associated documentation files (the "Software"), 
   to deal in the Software without restriction, including without limitation 
   the rights to use, copy, modify, merge, publish, distribute, sublicense, 
   and/or sell copies of the Software, and to permit persons to whom the 
   Software is furnished to do so, subject to the following conditions:
   
   The above copyright notice and this permission notice shall be 
   included in all copies or substantial portions of the Software.
*/ 
DhtmlHistory.POLLING_FREQUENCY = 300;
DhtmlHistory.WAIT_FREQUENCY = 500;
 function DhtmlHistory(storageMap, listenerFunction, parentObject) {
   this.locationOfBlankPage = UserContext.getUrl("/back_blank.html?");
	/** Our current hash location, without the "#" symbol. */
   this.currentLocation = null;
   this.listener = listenerFunction;
   /** A hidden IFrame we use in Internet Explorer to detect history
       changes. */
   this.iframe = null;
   /** Indicates to the browser whether to ignore location changes. */
   this.ignoreLocationChange = false;
   /** The amount of time in milliseconds an add request has to wait in line before being
       run on a window.setTimeout. */
   this.currentWaitTime = 0;
   this.historyStorage = storageMap;
   // initialization
   this.parentObject = parentObject;
   this.create();
}

DhtmlHistory.prototype.add = function(newLocation, historyData) {	
	// most browsers require that we wait a certain amount of time before changing the
	// location, such as 200 milliseconds; thus we internally handle this
	// detail by using a 'currentWaitTime' variable and have requests wait in line
	var self = this;
	var addImpl = function() {
	   // indicate that the current wait time is now less
	   if (self.currentWaitTime > 0) {
	      self.currentWaitTime = self.currentWaitTime - DhtmlHistory.WAIT_FREQUENCY;
	   }
	   // remove any leading hash symbols on newLocation
	   newLocation = self.removeHash(newLocation);
	   var idCheck = document.getElementById(newLocation);
	   if (idCheck) {
	      Gack.sendGack("History locations can not have the same value as any id's that might be in the document");
	      return; 
	   }
	   self.historyStorage[newLocation] = historyData;
	   // indicate to the browser to ignore this upcomming 
	   // location change
	   self.ignoreLocationChange = true;
	   // save this as our current location
	   self.currentLocation = newLocation;
	   // change the browser location
	   window.location.hash = newLocation;
	   // change the hidden iframe's location if on IE
	   if (XBrowser.userAgent.isIE){
	   		// write out a hidden iframe for IE and
	   		if(!self.iframe) {
		      	var b = document.getElementsByTagName('body')[0];
		      	if(!b){ return; }
		        var divElem = document.createElement('div');
		       	b.appendChild(divElem);
		       	divElem.style.display = 'none';
		        divElem.innerHTML = "<iframe class='dhtmlHistoryFrame' name='DhtmlHistoryFrame' id='DhtmlHistoryFrame' "
		                               + "src='"+ self.locationOfBlankPage + newLocation + "'></iframe>";
		         self.iframe = document.getElementById("DhtmlHistoryFrame");
	   	  } else {	
	      	self.iframe.src = self.locationOfBlankPage + newLocation;
	   	  }
	   }
	};
	// now execute this add request after waiting a certain amount of time, so as to
	// queue up requests
	 window.setTimeout(addImpl, this.currentWaitTime);
	 // indicate that the next request will have to wait for awhile
	 this.currentWaitTime = this.currentWaitTime + DhtmlHistory.WAIT_FREQUENCY;
}

/** Gets the current hash value that is in the browser's
       location bar, removing leading # symbols if they are present. */
DhtmlHistory.prototype.getCurrentLocation = function() {
	return this.removeHash(window.location.hash);
}
   
DhtmlHistory.prototype.create = function() {

      var initialHash = this.getCurrentLocation();
      this.currentLocation = initialHash;
      this.ignoreLocationChange = true;
      if(!XBrowser.userAgent.isIE){
      	var self = this;
      	var locationHandler = function() {
       	 	self.checkLocation();
      	};
      	setInterval(locationHandler, DhtmlHistory.POLLING_FREQUENCY);
      }
}
   
DhtmlHistory.prototype.fireHistoryEvent = function(oldHash, newHash) {
    this.listener.call(this.parentObject, oldHash, newHash);
}

DhtmlHistory.prototype.shouldProceedWithHistoryEvent = function () {
	if (this.ignoreLocationChange) {
       this.ignoreLocationChange = false;
       return false;
    } else {
    	return true;
    }
}

DhtmlHistory.prototype.checkLocation = function() {
   	if (XBrowser.userAgent.isIE || !this.shouldProceedWithHistoryEvent()){ return; }
    var hash = this.getCurrentLocation();
    if (hash == this.currentLocation) { return; }
    // save this new location
    var oldHash = this.currentLocation;
    this.currentLocation = hash;
    this.fireHistoryEvent(oldHash, hash);
}  
   
DhtmlHistory.prototype.removeHash = function(hashValue) {
    if (!hashValue){return null;}
    else if (hashValue == "" ||  (hashValue.length == 1 && hashValue.charAt(0) == "#")) { return ""; } 
    else if (hashValue.length > 1 && hashValue.charAt(0) == "#") { return hashValue.substring(1);} 
    else { return hashValue; }     
}          
   
DhtmlHistory.prototype.iframeLoaded = function(newLocation) {
    if (!XBrowser.userAgent.isIE || !this.shouldProceedWithHistoryEvent()){ return; }
    // get the new location
    var hash = new String(newLocation.search);
    if (!hash || (hash.length == 1 && hash.charAt(0) == "?")) {
       hash = "";
    } else if (hash.length >= 2 && hash.charAt(0) == "?") {
       hash = hash.substring(1);
    }
    
   	var oldHash = this.removeHash(window.location.hash);
    window.location.hash = hash;
    this.fireHistoryEvent(oldHash, hash);
}
/**
 * Material Copyrighted  2005, Brad Neuberg, bkn3@columbia.edu 
 * Modified by salesforce.com 2007
 * 
 * --------------------------------ENDS HERE-----------------------------------------
 */

/**
 *  UserInterfaceUI, the setup page for UI features
 *
 *  @author jwalters
 *  @since 156
 */

UserInterfaceUI.toggleCalendarPrefs = function() {
   var newListViewCheckbox = document.getElementById(UserInterfaceUI.pNEW_LIST_VIEW_NAME);
   var dragDropCheckbox = document.getElementById(UserInterfaceUI.pDRAG_AND_DROP_ON_CALENDAR_NAME);
   var clickCreateCheckbox = document.getElementById(UserInterfaceUI.pCLICK_AND_CREATE_ON_CALENDAR_NAME);
   var inlineSchedulingCheckbox = document.getElementById(UserInterfaceUI.pINLINE_SCHEDULING_NAME);
   var inlineSchedulingMessageBox = document.getElementById(UserInterfaceUI.pINLINE_SCHEDULING_NAME_MESSAGE);

   if (dragDropCheckbox.checked) {
     clickCreateCheckbox.disabled = false;
     if (clickCreateCheckbox.checked) {
       inlineSchedulingCheckbox.disabled = false;
         // if inline scheduling checkbox is checked, set the css class of the message box
         if (inlineSchedulingCheckbox.checked && !(newListViewCheckbox != null && newListViewCheckbox.checked)) {
           inlineSchedulingMessageBox.className = "message infoM4 twoindent";
         }
         else {
             // if inline scheduling check box is unchecked, hide the message
            inlineSchedulingMessageBox.className = "hideblock";
         }
     } else {
       inlineSchedulingCheckbox.disabled = true;

       // if click and create checkbox is unchecked, uncheck inline scheduing check box and hide inline scheduling message
       inlineSchedulingCheckbox.checked = false;
       inlineSchedulingMessageBox.className = "hideblock";
     }
   } else {
     clickCreateCheckbox.disabled = true;

     // if drag and drop check box is unchecked, uncheck click and create checkbox; uncheck inline scheduing checkbox; hide
     // inline scheduing message
     clickCreateCheckbox.checked = false;
     inlineSchedulingCheckbox.disabled = true;
     inlineSchedulingCheckbox.checked = false;
     inlineSchedulingMessageBox.className = "hideblock";
   }
}
/**
 *  ActivityHover.js, extends Hover class, and is used for Activities such as Events and Tasks
 *
 *  @author eli
 *  @since 146 (rewrite of 144 code in functions.js)
 */

ActivityHover.prototype = new Hover();

function ActivityHover() {
}

ActivityHover.getHover = function(elementId) {
    var hover = Hover.hoverMap[elementId];
    if (typeof hover == 'undefined') {
		return Hover.createHover(new ActivityHover(), elementId);
    }
    return hover;
}

ActivityHover.prototype.loadHook_afterLoad = function() {
    var contentObj = getElementByIdCS(this.eid + "_content");
    var pbSubsectionObj = DomUtil.findDescendantWithClassName(contentObj, 'pbSubsection');
    if (pbSubsectionObj) {
        var detailListObj = DomUtil.findDescendantWithClassName(pbSubsectionObj, 'detailList');

        // Increase width of hover if the contents are too big to fit inside
        if (Hover.getElementWidth(detailListObj) > Hover.getElementWidth(pbSubsectionObj)) {
            var diff = Hover.getElementWidth(detailListObj) - Hover.getElementWidth(pbSubsectionObj);
            contentObj.style.width = (Hover.getElementWidth(contentObj) + diff) + 'px';
            pbSubsectionObj.style.width = Hover.getElementWidth(detailListObj) + 'px';
        }
    }
}

ActivityHover.prototype.setXPos = function(x) {
	var minX = this.getMinX();
	var maxX = this.getMaxX();

    /** Implements a 75px wide 'safezone' where a hover will never appear so that it doesn't cover up the element
     *  If maxX is below this safezone position, then the maxX is adjusted to the left of the element,
     *  and if x is below the safezone line, then we move that as our mouse position. Then if x>maxX, we move x back down
     *  to the max so the hover doesn't go too far right or cover up our safezone.
     *  Also implements an expanding hover that will expand in case the contents do not fit inside the box. This will happen in
     *  the case of long character strings that dont break up into mulitple lines.
     */
    var srcEleWidth = this.xObjRight-this.xObjLeft;
    var offset = (srcEleWidth < 75) ? srcEleWidth : 75;

    var maximum = Math.max(this.xObjLeft - minX, maxX + Hover.getElementWidth(this.ele) - this.xObjLeft - offset);
    if (maximum < 200) maximum = 200;

    if (Hover.getElementWidth(this.ele) > maximum) {
        var contentObj = getElementByIdCS(this.eid + "_content");
        var pbSubsectionObj = DomUtil.findDescendantWithClassName(contentObj, 'pbSubsection');
        // Skip over this code if there is no detail layout hover
        if (pbSubsectionObj) {
            var contentSubsectionDiff = Hover.getElementWidth(contentObj) - Hover.getElementWidth(pbSubsectionObj);
            var hoverContentDiff = Hover.getElementWidth(this.ele)-Hover.getElementWidth(contentObj);
            contentObj.style.width = (maximum - hoverContentDiff) + 'px';
            pbSubsectionObj.style.width = (Hover.getElementWidth(contentObj) - contentSubsectionDiff) + 'px';
            /* This prevents bad behavior on extremely small screens. If the hover did no
