} // 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());
        }
        public JobPostingDetailsData getJobPostingDetailsData(CmsPage page, int identifier, CmsLanguage language, bool createNewIfDoesNotExist)
        {
            if (page.Id < 0 || identifier < 0)
            {
                return(new JobPostingDetailsData());
            }

            string sql = "";

            sql  = "select * from jobdetails s ";
            sql += " where s.pageid = " + page.Id.ToString() + " and s.identifier = " + identifier.ToString() + " and langShortCode = '" + dbEncode(language.shortCode) + "' and s.deleted is null;";

            DataSet ds = this.RunSelectQuery(sql);

            if (this.hasSingleRow(ds))
            {
                JobPostingDetailsData data = new JobPostingDetailsData();
                DataRow dr = ds.Tables[0].Rows[0];

                data.JobId              = Convert.ToInt32(dr["JobId"]);
                data.LocationId         = Convert.ToInt32(dr["JobLocationId"]);
                data.RemoveAnonAccessAt = Convert.ToDateTime(dr["RemoveAnonAccessAt"].ToString());

                return(data);
            }
            else
            {
                if (createNewIfDoesNotExist)
                {
                    JobPostingDetailsData data = new JobPostingDetailsData();
                    bool b = createNewJobPostingDetailsData(page, identifier, language, data);

                    if (!b)
                    {
                        throw new Exception("getJobPostingDetailsData database error: Error creating new placeholder");
                    }
                    else
                    {
                        return(data);
                    }
                }
                else
                {
                    throw new Exception("getJobPostingDetailsData database error: placeholder does not exist");
                }
            }
        } // getJobPostingDetailsData
        }  // createNewJobPostingDetailsData

        public bool saveUpdatedJobPostingDetailsData(JobPostingDetailsData data)
        {
            if (data.JobId < 0)
            {
                return(false);
            }

            string sql = "update jobdetails set ";

            sql += " JobLocationId = " + data.LocationId.ToString() + ", ";
            sql += " RemoveAnonAccessAt = " + dbEncode(data.RemoveAnonAccessAt) + " ";
            sql += " where JobId = " + data.JobId.ToString();

            int numAffected = this.RunUpdateQuery(sql);

            return(numAffected > 0);
        }
        } // 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 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
        } // getJobPostingDetailsData

        public bool createNewJobPostingDetailsData(CmsPage page, int identifier, CmsLanguage language, JobPostingDetailsData data)
        {
            string sql = "insert into jobdetails (pageid, identifier, langShortCode, JobLocationId, RemoveAnonAccessAt) values (";

            sql += page.Id.ToString() + "," + identifier.ToString() + ",";
            sql += "'" + dbEncode(language.shortCode) + "', ";
            sql += "" + (data.LocationId.ToString()) + ", ";
            sql += "" + dbEncode(data.RemoveAnonAccessAt) + " ";
            sql += "); ";

            int newId = this.RunInsertQuery(sql);

            if (newId > -1)
            {
                data.JobId = newId;

                return(page.setLastUpdatedDateTimeToNow());
            }
            else
            {
                return(false);
            }
        }  // createNewJobPostingDetailsData