/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  The ASF licenses this file to You
 * under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.  For additional information regarding
 * copyright in this work, please see the NOTICE file in the top level
 * directory of this distribution.
 */

package org.apache.roller.weblogger.ui.struts2.editor;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.WeblogEntryManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
import org.apache.roller.weblogger.pojos.WeblogCategory;
import org.apache.roller.weblogger.pojos.WeblogEntry;
import org.apache.roller.weblogger.pojos.WeblogEntry.PubStatus;
import org.apache.roller.weblogger.pojos.WeblogEntryAttribute;
import org.apache.roller.weblogger.util.Utilities;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;


/**
 * Bean for managing entry data.
 */
public class EntryBean {
    
    private static final Log log = LogFactory.getLog(EntryBean.class);
    
    private String id = null;
    private String title = null;
    private String locale = null;
    private String categoryId = null;
    private String tagsString = null;
    private String summary = null;
    private String text = null;
    private String status = null;

    private String[] plugins = null;
    private String dateString = null;
    private int hours = 0;
    private int minutes = 0;
    private int seconds = 0;
    private boolean allowComments = true;
    private Integer commentDays = 0;
    private boolean rightToLeft = false;
    private boolean pinnedToMain = false;
    private String enclosureURL = null;
    private String searchDescription = null;
    private int commentCount = 0;
    
    
    public String getId() {
        return this.id;
    }
    
    public void setId( String id ) {
        this.id = id;
    }
    
    public String getTitle() {
        return this.title;
    }
    
    public void setTitle( String title ) {
        this.title = title;
    }
    
    public String getSummary() {
        return this.summary;
    }
    
    public void setSummary( String summary ) {
        this.summary = summary;
    }
    
    public String getText() {
        return this.text;
    }
    
    public void setText( String text ) {
        this.text = text;
    }
    
    public String getStatus() {
        return this.status;
    }
    
    public void setStatus( String status ) {
        this.status = status;
    }
    
    public String getLocale() {
        return this.locale;
    }
    
    public void setLocale( String locale ) {
        this.locale = locale;
    }
    
    public String getTagsAsString() {
        return this.tagsString;
    }
    
    public void setTagsAsString( String tagsAsString ) {
        this.tagsString = tagsAsString;
    }
    
    public String getCategoryId() {
        return categoryId;
    }
    
    public void setCategoryId(String categoryId) {
        this.categoryId = categoryId;
    }
    
    
    public String[] getPlugins() {
        return this.plugins;
    }
    
    public void setPlugins(String[] plugins ) {
        this.plugins = plugins;
    }
    
    public String getDateString() {
        return dateString;
    }
    
    public void setDateString(String date) {
        this.dateString = date;
    }
    
    public int getHours() {
        return hours;
    }
    
    public void setHours(int hours) {
        this.hours = hours;
    }
    
    public int getMinutes() {
        return minutes;
    }
    
    public void setMinutes(int minutes) {
        this.minutes = minutes;
    }
    
    public int getSeconds() {
        return seconds;
    }
    
    public void setSeconds(int seconds) {
        this.seconds = seconds;
    }
    
    public boolean getAllowComments() {
        return this.allowComments;
    }
    
    public void setAllowComments( boolean allowComments ) {
        this.allowComments = allowComments;
    }
    
    public Integer getCommentDays() {
        return this.commentDays;
    }
    
    public void setCommentDays(Integer commentDays) {
        this.commentDays = commentDays;
        if (commentDays == -1) {
            allowComments = false;
        }
    }
    
    public int getCommentCount() {
        return commentCount;
    }

    public void setCommentCount(int commentCount) {
        this.commentCount = commentCount;
    }

    public boolean getRightToLeft() {
        return this.rightToLeft;
    }
    
    public void setRightToLeft( boolean rightToLeft ) {
        this.rightToLeft = rightToLeft;
    }
    
    public boolean getPinnedToMain() {
        return this.pinnedToMain;
    }
    
    public void setPinnedToMain( boolean pinnedToMain ) {
        this.pinnedToMain = pinnedToMain;
    }
    
    public String getEnclosureURL() {
        return enclosureURL;
    }
    
    public void setEnclosureURL(String enclosureUrl) {
        this.enclosureURL = enclosureUrl;
    }
    
    public String getSearchDescription() {
        return searchDescription;
    }
    
    public void setSearchDescription(String searchDescription) {
        this.searchDescription = searchDescription;
    }
    
    // a convenient way to get the final pubtime of the entry
    public Timestamp getPubTime(Locale locale, TimeZone timezone) {
        
        Timestamp pubtime = null;
        
        if(!StringUtils.isEmpty(getDateString())) {
            try {
                log.debug("pubtime vals are "+getDateString()+", "+getHours()+", "+getMinutes()+", "+getSeconds());

                // first convert the specified date string into an actual Date obj
                // TODO: at some point this date conversion should be locale sensitive,
                // however at this point our calendar widget does not take into account
                // locales and only operates in the standard English US locale.

                // Don't require user add preceding '0' of month and day.
                DateFormat df = new SimpleDateFormat("M/d/yy");
                df.setTimeZone(timezone);
                Date newDate = df.parse(getDateString());

                log.debug("dateString yields date - "+newDate);

                // Now handle the time from the hour, minute and second combos
                Calendar cal = Calendar.getInstance(timezone,locale);
                cal.setTime(newDate);
                cal.set(Calendar.HOUR_OF_DAY, getHours());
                cal.set(Calendar.MINUTE, getMinutes());
                cal.set(Calendar.SECOND, getSeconds());
                pubtime = new Timestamp(cal.getTimeInMillis());

                log.debug("pubtime is "+pubtime);
            } catch(Exception e) {
                log.error("Error calculating pubtime", e);
            }
        }
        
        return pubtime;
    }
    
    public boolean isDraft() {
        return PubStatus.DRAFT.name().equals(status);
    }
    
    public boolean isPending() {
        return PubStatus.PENDING.name().equals(status);
    }
    
    public boolean isPublished() {
        return PubStatus.PUBLISHED.name().equals(status);
    }
    
    public boolean isScheduled() {
        return PubStatus.SCHEDULED.name().equals(status);
    }
    
    public void copyTo(WeblogEntry entry) throws WebloggerException {
        
        entry.setTitle(StringEscapeUtils.escapeHtml4(getTitle()));
        entry.setStatus(PubStatus.valueOf(getStatus()));
        entry.setLocale(getLocale());
        entry.setSummary(getSummary());
        entry.setText(getText());
        entry.setTagsAsString(Utilities.replaceNonAlphanumeric(getTagsAsString(), ' '));
        entry.setSearchDescription(getSearchDescription());
        
        // figure out the category selected
        if (getCategoryId() != null) {
            WeblogCategory cat = null;
            try {
                WeblogEntryManager wmgr = WebloggerFactory.getWeblogger().getWeblogEntryManager();
                cat = wmgr.getWeblogCategory(getCategoryId());
            } catch (WebloggerException ex) {
                log.error("Error getting category by id", ex);
            }
            
            if(cat == null) {
                throw new WebloggerException("Category could not be found - "+getCategoryId());
            } else if(!entry.getWebsite().equals(cat.getWeblog())) {
                throw new WebloggerException("Illegal category, not owned by action weblog");
            } else {
                entry.setCategory(cat);
            }
        } else {
            throw new WebloggerException("No category specified");
        }
        
        // join values from all plugins into a single string
        entry.setPlugins(StringUtils.join(getPlugins(),","));
        
        // comment settings & right-to-left option
        entry.setAllowComments(getAllowComments());
        entry.setCommentDays(getCommentDays());
        entry.setRightToLeft(getRightToLeft());
        
        // NOTE: pubtime and pinned to main attributes are set in action
    }
    
    
    /**
     * Copy values from WeblogEntryData to this Form.
     */
    public void copyFrom(WeblogEntry entry, Locale locale) {
        
        setId(entry.getId());
        setTitle(StringEscapeUtils.unescapeHtml4(entry.getTitle()));
        setLocale(entry.getLocale());
        setStatus(entry.getStatus().name());
        setSummary(entry.getSummary());
        setText(entry.getText());
        setCategoryId(entry.getCategory().getId());
        setTagsAsString(entry.getTagsAsString());
        setSearchDescription(entry.getSearchDescription());
        
        // set comment count, ignoreSpam=false, approvedOnly=false
        setCommentCount(entry.getComments(false, false).size());
        
        // init plugins values
        if(entry.getPlugins() != null) {
            setPlugins(StringUtils.split(entry.getPlugins(), ","));
        }
        
        // init pubtime values
        if(entry.getPubTime() != null) {
            log.debug("entry pubtime is "+entry.getPubTime());
            
            //Calendar cal = Calendar.getInstance(locale);
            Calendar cal = Calendar.getInstance();
            cal.setTime(entry.getPubTime());
            cal.setTimeZone(entry.getWebsite().getTimeZoneInstance());
            
            setHours(cal.get(Calendar.HOUR_OF_DAY));
            setMinutes(cal.get(Calendar.MINUTE));
            setSeconds(cal.get(Calendar.SECOND));
            
            // TODO: at some point this date conversion should be locale sensitive,
            // however at this point our calendar widget does not take into account
            // locales and only operates in the standard English US locale.
            DateFormat df = new SimpleDateFormat("MM/dd/yy");
            df.setTimeZone(entry.getWebsite().getTimeZoneInstance());
            setDateString(df.format(entry.getPubTime()));
            
            log.debug("pubtime vals are "+getDateString()+", "+getHours()+", "+getMinutes()+", "+getSeconds());
        }
        
        setAllowComments(entry.getAllowComments());
        setCommentDays(entry.getCommentDays());
        setRightToLeft(entry.getRightToLeft());
        setPinnedToMain(entry.getPinnedToMain());
        
        // enclosure url, if it exists
        Set<WeblogEntryAttribute> attrs = entry.getEntryAttributes();
        if(attrs != null && !attrs.isEmpty()) {
            for (WeblogEntryAttribute attr : attrs) {
                if ("att_mediacast_url".equals(attr.getName())) {
                    setEnclosureURL(attr.getValue());
                }
            }
        }
    }
    
    
    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        
        //title,locale,catId,tags,text,summary,dateString,status,comments,plugins
        buf.append("title = ").append(getTitle()).append("\n");
        buf.append("locale = ").append(getLocale()).append("\n");
        buf.append("status = ").append(getStatus()).append("\n");
        buf.append("catId = ").append(getCategoryId()).append("\n");
        buf.append("tags = ").append(getTagsAsString()).append("\n");
        buf.append("date = ").append(getDateString()).append("\n");
        buf.append("hours = ").append(getHours()).append("\n");
        buf.append("minutes = ").append(getMinutes()).append("\n");
        buf.append("seconds = ").append(getSeconds()).append("\n");
        buf.append("text = ").append(getText()).append("\n");
        buf.append("summary = ").append(getSummary()).append("\n");
        buf.append("search description = ").append(getSearchDescription()).append("\n");
        buf.append("comments = ").append(getAllowComments()).append("\n");
        buf.append("commentDays = ").append(getCommentDays()).append("\n");
        buf.append("plugins = ").append(Arrays.toString(getPlugins())).append("\n");
        
        return buf.toString();
    }
}
