} // RenderEdit

        public override Rss.RssItem[] GetRssFeedItems(CmsPage page, CmsPlaceholderDefinition placeholderDefinition, CmsLanguage langToRenderFor)
        {
            List <Rss.RssItem> ret = new List <Rss.RssItem>();
            Dictionary <CmsPage, CmsPlaceholderDefinition[]> childJobPages = CmsContext.getAllPlaceholderDefinitions("JobPostingDetails", page, CmsContext.PageGatheringMode.ChildPagesOnly);

            if (childJobPages.Count > 0)
            {
                JobPostingLocation[] allLocations            = JobPostingLocation.FetchAll();
                JobPostingLocation   theAllLocationsLocation = JobPostingLocation.getAllLocations(allLocations);

                JobPostingDb             db             = new JobPostingDb();
                JobPostingAggregatorData aggregatorData = db.getJobPostingAggregatorData(page, placeholderDefinition.Identifier, langToRenderFor, true);

                // -- grab all the details for all child job pages.


                foreach (CmsPage childPage in childJobPages.Keys)
                {
                    foreach (CmsPlaceholderDefinition phDef in childJobPages[childPage])
                    {
                        JobPostingDetailsData dataObj = db.getJobPostingDetailsData(childPage, phDef.Identifier, langToRenderFor, true);
                        if (!dataObj.IsExpired && (aggregatorData.LocationId < 0 || aggregatorData.LocationId == theAllLocationsLocation.JobLocationId || dataObj.LocationId == aggregatorData.LocationId))
                        {
                            Rss.RssItem rssItem = CreateAndInitRssItem(childPage, langToRenderFor);
                            rssItem.Description = childPage.renderAllPlaceholdersToString(langToRenderFor, CmsPage.RenderPlaceholderFilterAction.RunAllPageAndPlaceholderFilters);
                            ret.Add(rssItem);
                        }
                    }
                } // foreach child page
            }


            return(ret.ToArray());
        }
        /// <summary>
        /// Renders the placeholder in ViewMode
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="page"></param>
        /// <param name="identifier"></param>
        /// <param name="langToRenderFor"></param>
        /// <param name="paramList"></param>
        public override void RenderInViewMode(HtmlTextWriter writer, CmsPage page, int identifier, CmsLanguage langToRenderFor, string[] paramList)
        {
            AddJobPostingCommandToEditMenu(page, page);

            Dictionary <CmsPage, CmsPlaceholderDefinition[]> childJobPages = CmsContext.getAllPlaceholderDefinitions("JobPostingDetails", page, CmsContext.PageGatheringMode.FullRecursion);

            JobPostingLocation[] allLocations            = JobPostingLocation.FetchAll();
            JobPostingLocation   theAllLocationsLocation = JobPostingLocation.getAllLocations(allLocations);

            JobPostingDb             db             = new JobPostingDb();
            JobPostingAggregatorData aggregatorData = db.getJobPostingAggregatorData(page, identifier, langToRenderFor, true);

            // -- grab all the details for all child job pages.

            Dictionary <CmsPage, List <JobPostingDetailsData> > childJobDetails = new Dictionary <CmsPage, List <JobPostingDetailsData> >();

            foreach (CmsPage childPage in childJobPages.Keys)
            {
                childJobDetails[childPage] = new List <JobPostingDetailsData>();
                foreach (CmsPlaceholderDefinition phDef in childJobPages[childPage])
                {
                    JobPostingDetailsData dataObj = db.getJobPostingDetailsData(childPage, phDef.Identifier, langToRenderFor, true);
                    childJobDetails[childPage].Add(dataObj);
                }
            } // foreach child page

            // -- do HTML output only for the location
            StringBuilder html       = new StringBuilder();
            bool          jobsOutput = false;

            foreach (JobPostingLocation location in allLocations)
            {
                if (aggregatorData.LocationId < 0 || aggregatorData.LocationId == theAllLocationsLocation.JobLocationId || location.JobLocationId == aggregatorData.LocationId)
                {
                    string jobHtml = getHtmlForJobsInLocation(childJobDetails, location, langToRenderFor);
                    if (jobHtml != "")
                    {
                        html.Append(jobHtml);
                        jobsOutput = true;
                    }
                }
            } // foreach

            if (!jobsOutput)
            {
                html.Append("<p class=\"noJobsMessage\">There are currently no jobs available</p>");
            }

            writer.Write(html.ToString());
        }
        /// <summary>
        /// Renders the placeholder in EditMode
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="page"></param>
        /// <param name="identifier"></param>
        /// <param name="langToRenderFor"></param>
        /// <param name="paramList"></param>
        public override void RenderInEditMode(HtmlTextWriter writer, CmsPage page, int identifier, CmsLanguage langToRenderFor, string[] paramList)
        {
            string       placeholderId = "JobAggregatorDetails_" + page.Id.ToString() + "_" + identifier.ToString() + langToRenderFor.shortCode;
            JobPostingDb db            = new JobPostingDb();

            JobPostingAggregatorData aggregatorData = db.getJobPostingAggregatorData(page, identifier, langToRenderFor, true);

            JobPostingLocation[] locations    = JobPostingLocation.FetchAll();
            JobPostingLocation   AllLocations = JobPostingLocation.getAllLocations(locations);

            // ------- CHECK THE FORM FOR ACTIONS
            string action = PageUtils.getFromForm(placeholderId + "_Action", "");

            if (action.Trim().ToLower() == "update")
            {
                // save the data to the database

                int newLocationId = PageUtils.getFromForm("location_" + placeholderId, AllLocations.JobLocationId);

                aggregatorData.LocationId = newLocationId;

                bool b = db.saveUpdatedJobPostingAggregatorData(aggregatorData);
                if (!b)
                {
                    writer.Write("Error saving updates to database!");
                }
            }
            StringBuilder html = new StringBuilder();

            html.Append("<div class=\"JobPostingAggregator Edit\">");
            html.Append("<table width=\"100%\" border=\"0\">");

            // -- Job Location drop-down

            html.Append("<tr>");
            html.Append("<td>Job Location To Display:</td>");
            html.Append("</tr>");
            html.Append("<tr>");

            html.Append("<td>" + PageUtils.getDropDownHtml("location_" + placeholderId, "location_" + placeholderId, JobPostingLocation.ToNameValueCollection(locations, CmsContext.currentLanguage, true), aggregatorData.LocationId.ToString()) + "</td>");
            html.Append("</tr>");

            html.Append("</table>" + Environment.NewLine);

            html.Append(PageUtils.getHiddenInputHtml(placeholderId + "_Action", "update"));

            html.Append("</div>" + Environment.NewLine);

            writer.Write(html.ToString());
        } // RenderEdit
            } // Update

            private JobPostingLocation GetFromRow(DataRow dr)
            {
                JobPostingLocation item = new JobPostingLocation();

                item.JobLocationId = Convert.ToInt32(dr["JobLocationId"]);

                item.LocationText = (dr["LocationText"]).ToString();

                item.IsAllLocations = Convert.ToBoolean(dr["IsAllLocations"]);

                item.SortOrdinal = Convert.ToInt32(dr["SortOrdinal"]);

                return(item);
            } // GetFromRow
            } // Insert

            public bool Update(JobPostingLocation item)
            {
                string sql = "UPDATE joblocations SET ";

                sql += "LocationText = " + "'" + dbEncode(item.LocationText) + "'" + ", ";
                sql += "IsAllLocations = " + Convert.ToInt32(item.IsAllLocations).ToString() + ", ";
                sql += "SortOrdinal = " + item.SortOrdinal.ToString() + " ";
                sql += " WHERE JobLocationId = " + item.JobLocationId.ToString();
                sql += " ; ";

                int numAffected = this.RunUpdateQuery(sql);

                if (numAffected < 0)
                {
                    return(false);
                }
                return(true);
            } // Update
        } // RenderEdit

        public override void RenderInViewMode(HtmlTextWriter writer, CmsPage page, int identifier, CmsLanguage langToRenderFor, string[] paramList)
        {
            // -- revise the Edit Menu
            CmsPage aggregatorPage = page.ParentPage;

            JobPostingAggregator.AddJobPostingCommandToEditMenu(page, aggregatorPage);

            JobPostingDb          db             = new JobPostingDb();
            JobPostingDetailsData postingDetails = db.getJobPostingDetailsData(page, identifier, langToRenderFor, true);
            JobPostingLocation    location       = JobPostingLocation.Fetch(postingDetails.LocationId);
            StringBuilder         html           = new StringBuilder();

            html.Append("<div class=\"JobPostingDetails View\">");

            if (IncludeBackLinkInDisplay)
            {
                string aggregatorUrl = aggregatorPage.Url;
                html.Append("<p class=\"jobBackToAggregator\"><strong><a class=\"backToPrev\" href=\"" + aggregatorUrl + "\">" + getBackToJobListingText(langToRenderFor) + "</a></strong><p>");
            }

            // -- if the posting is expired, don't let non-authors view it.
            if (postingDetails.IsExpired && !page.currentUserCanWrite)
            {
                throw new CmsPageNotFoundException();
            }

            if (page.currentUserCanWrite && postingDetails.IsExpired)
            {
                html.Append("<div class=\"jobExpiredNotice\" style=\"background-color: yellow; font-weight: bold\">This job posting expired on " + postingDetails.RemoveAnonAccessAt.ToString("d MMM yyyy") + "</div> ");
            }
            else if (page.currentUserCanWrite && postingDetails.RemoveAnonAccessAt.Date != JobPostingDetailsData.NoExpiryDateTime.Date)
            {
                html.Append("<p class=\"jobExpiredNotice\" style=\"background-color: yellow; font-weight: bold\">This job will be removed from public access on " + postingDetails.RemoveAnonAccessAt.ToString("d MMM yyyy") + "</p>");
            }

            if (IncludeLocationInDisplay)
            {
                html.Append("<p class=\"jobLocation\">" + getLocationText(langToRenderFor) + ": " + location.getLocationText(langToRenderFor) + "</p>");
            }

            html.Append("</div>" + Environment.NewLine);

            writer.Write(html.ToString());
        } // RenderView
            public bool Insert(JobPostingLocation item)
            {
                string sql = "INSERT INTO joblocations ";

                sql += "(LocationText, IsAllLocations, SortOrdinal)";
                sql += " VALUES ( ";
                sql += "'" + dbEncode(item.LocationText) + "'" + ", ";
                sql += Convert.ToInt32(item.IsAllLocations).ToString() + ", ";
                sql += item.SortOrdinal.ToString() + " ";
                sql += " ); ";

                int newId = this.RunInsertQuery(sql);

                if (newId > -1)
                {
                    item.JobLocationId = newId;
                    return(true);
                }
                return(false);
            } // Insert
        public static JobPostingDetailsData[] GetForLocation(JobPostingDetailsData[] haystack, JobPostingLocation locationToFind)
        {
            List <JobPostingDetailsData> ret = new List <JobPostingDetailsData>();

            foreach (JobPostingDetailsData job in haystack)
            {
                if (job.LocationId == locationToFind.JobLocationId)
                {
                    ret.Add(job);
                }
            } // foreach
            return(ret.ToArray());
        }
        public override void RenderInEditMode(HtmlTextWriter writer, CmsPage page, int identifier, CmsLanguage langToRenderFor, string[] paramList)
        {
            string                placeholderId            = "JobPostingDetails_" + page.Id.ToString() + "_" + identifier.ToString() + langToRenderFor.shortCode;
            string                placeholderIdWithoutLang = "location_JobPostingDetails_" + page.Id.ToString() + "_" + identifier.ToString();
            JobPostingDb          db             = new JobPostingDb();
            JobPostingDetailsData postingDetails = db.getJobPostingDetailsData(page, identifier, langToRenderFor, true);

            JobPostingLocation[] locations    = JobPostingLocation.FetchAll();
            JobPostingLocation   AllLocations = JobPostingLocation.getAllLocations(locations);

            // ------- CHECK THE FORM FOR ACTIONS
            string action = PageUtils.getFromForm(placeholderId + "_Action", "");

            if (action.Trim().ToLower() == "update")
            {
                // save the data to the database

                int    newLocationId = PageUtils.getFromForm("location_" + placeholderId, AllLocations.JobLocationId);
                string dateStr       = PageUtils.getFromForm("RemoveAnonAccessAt_" + placeholderId, "");

                postingDetails.LocationId         = newLocationId;
                postingDetails.RemoveAnonAccessAt = CmsConfig.parseDateInDateInputFormat(dateStr, postingDetails.RemoveAnonAccessAt);

                bool b = db.saveUpdatedJobPostingDetailsData(postingDetails);
                if (!b)
                {
                    writer.Write("Error saving updates to database!");
                }
            }
            StringBuilder html = new StringBuilder();

            html.Append("<div class=\"JobPostingDetails Edit\">");
            html.Append("<table width=\"100%\" border=\"0\">");

            html.Append("<tr>");
            html.Append("<td>Date to remove public access:</td>");
            html.Append("</tr>");
            html.Append("<tr>");
            html.Append("<td>");
            html.Append(PageUtils.getInputTextHtml("RemoveAnonAccessAt_" + placeholderId, "RemoveAnonAccessAt_" + placeholderId, postingDetails.RemoveAnonAccessAt.ToString(CmsConfig.InputDateTimeFormatInfo), 12, 10));
            html.Append(" <em>format: " + CmsConfig.InputDateTimeFormatInfo.ToUpper() + ". ");
            html.Append("Enter '" + DateTime.MaxValue.ToString(CmsConfig.InputDateTimeFormatInfo) + "' for no auto-removal</em>.</td>");
            html.Append("</tr>");

            // -- Job Location drop-down

            html.Append("<tr>");
            html.Append("<td>Job Location:</td>");
            html.Append("</tr>");
            html.Append("<tr>");

            html.Append("<td>" + PageUtils.getDropDownHtml("location_" + placeholderId, "location_" + placeholderId, JobPostingLocation.ToNameValueCollection(locations, langToRenderFor, AllowPostingToAllLocations), postingDetails.LocationId.ToString()));

            try
            {
                CmsPage editLocationPage = CmsContext.getPageByPath("_admin/JobLocation");
                html.Append(" <a href=\"" + editLocationPage.getUrl(langToRenderFor) + "\" onclick=\"window.open(this.href,'" + placeholderIdWithoutLang + "','resizable=1,scrollbars=1,width=800,height=400'); return false;\">(edit)</a>");
            }
            catch (Exception ex)
            {
                html.Append(" <span>Cannot setup Edit Category Link: " + ex.Message + "</span>");
            }

            html.Append("</td>");
            html.Append("</tr>");

            html.Append("</table>" + Environment.NewLine);

            html.Append(PageUtils.getHiddenInputHtml(placeholderId + "_Action", "update"));

            html.Append("</div>" + Environment.NewLine);

            writer.Write(html.ToString());
        } // RenderEdit
        private string getHtmlForJobsInLocation(Dictionary <CmsPage, List <JobPostingDetailsData> > haystack, JobPostingLocation location, CmsLanguage langToDisplay)
        {
            int           numJobsToDisplay = 0;
            StringBuilder html             = new StringBuilder();

            html.Append("<h2 class=\"JobLocation\">" + location.getLocationText(langToDisplay) + "</h2>" + Environment.NewLine);
            html.Append("<ul>" + Environment.NewLine);

            foreach (CmsPage jobPage in haystack.Keys)
            {
                foreach (JobPostingDetailsData job in haystack[jobPage])
                {
                    if (job.LocationId == location.JobLocationId)
                    {
                        if (job.IsExpired)
                        {
                            html.Append("<span class=\"jobExpiredNotice\" style=\"background-color: yellow; font-weight: bold\">EXPIRED:</span> ");
                        }
                        html.Append("<strong>");
                        html.Append(jobPage.Title);
                        html.Append("</strong>");
                        html.Append(" <a class=\"rightArrowLink\" href=\"" + jobPage.Url + "\">" + getFullJobDescriptionText(langToDisplay) + "</a>" + Environment.NewLine);
                        html.Append("<br><br>");
                        numJobsToDisplay++;
                    }
                } // foreach job
            }     // foreach page


            html.Append("</ul>" + Environment.NewLine);

            if (numJobsToDisplay == 0)
            {
                return("");
            }

            return(html.ToString());
        }
        } // FetchAll

        private static int CompareBySortOrdinal(JobPostingLocation x, JobPostingLocation y)
        {
            return(x.SortOrdinal.CompareTo(y.SortOrdinal));
        }