package jp.sourceforge.shovel.action.impl;

import static jp.sourceforge.shovel.SessionConst.*;
import static jp.sourceforge.shovel.ViewType.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.ArrayUtils;
import org.seasar.framework.container.S2Container;

import jp.sourceforge.shovel.FormatType;
import jp.sourceforge.shovel.action.IFriendsTimelineAction;
import jp.sourceforge.shovel.annotation.Perform;
import jp.sourceforge.shovel.entity.IFriendship;
import jp.sourceforge.shovel.entity.IListRefine;
import jp.sourceforge.shovel.entity.IStatus;
import jp.sourceforge.shovel.entity.IUser;
import jp.sourceforge.shovel.exception.ApplicationException;
import jp.sourceforge.shovel.form.IStatusesForm;
import jp.sourceforge.shovel.service.IDirectoryService;
import jp.sourceforge.shovel.service.IShovelService;

public class FriendsTimelineActionImpl implements IFriendsTimelineAction {
    IStatusesForm actionForm_;
    HttpServletRequest request_;
    HttpServletResponse response_;
    S2Container container_;
    
    @Perform(CSRF=false, login=false)
    public String perform() throws Exception {
        IShovelService shovelService = getShovelService();
        IDirectoryService directoryService = shovelService.getDirectoryService();
        String foreignKey = actionForm_.getForeignKey();
        long userId = actionForm_.getUserId();
        IUser user = null;
        boolean home = false;
        if (foreignKey == null || foreignKey.length() <= 0) {
            user = directoryService.getLoginUser();
            home = true;
        } else if (foreignKey.matches("^[0-9]+$")) {
            user = directoryService.getUser(userId);
        } else {
            user = directoryService.getUser(foreignKey);
        }
        if (user == null) {
            throw new ApplicationException("");
        }
        
        FormatType formatType = actionForm_.getFormatType();
        
        boolean protect = false;
        if (!home && user.isProtect()) {
            protect = true;
            IUser login = directoryService.getLoginUser();
            if (login != null) {
                if (login.getUserId() == user.getUserId()) {
                    protect = false;
                } else {
                    IFriendship[] friends = shovelService.getRequests(user.getUserId());
                    //アクセスが許可されるのは次のケース
                    for (IFriendship tmp : friends) {
                        if (tmp.getRemovedTime() > 0) {
                            continue;
                        }
                        if (tmp.getPassiveId() == user.getUserId()) {
                            //1. 明示的にアクセスを許可される
                            protect &= !tmp.isAccept();
                            request_.setAttribute("friend", tmp);
                        } else {
                            //2. プロテクトしている側からフォロー
                            if (login.isProtect()) {
                                //3. ログインユーザがプロテクトしているなら明示的なアクセスの許可が必要
                                protect &= !tmp.isAccept();
                            } else {
                                protect &= false;
                            }
                            request_.setAttribute("follower", tmp);
                        }
                    }
                }
            }
        }
        
        int page = actionForm_.getPage();
        String since = actionForm_.getSince();
        int limit = actionForm_.getCount();
        IListRefine listRefine = null;
        IStatus[] statuses = new IStatus[0];
        IStatus[] temp = null;
        IStatus status = null;
        listRefine = (IListRefine)getSession().getAttribute(S_LIST_REFINE);
        if (listRefine == null || !(listRefine.getViewType().isFriendsTimeline() ||
            listRefine.getViewType().isRecent() || listRefine.getViewType().isWithFriends())) {
            listRefine = (IListRefine)container_.getComponent(IListRefine.class);
            getSession().setAttribute(S_LIST_REFINE, listRefine);
        } else if (actionForm_.getMethodType().isPage()) {
            listRefine.setPage(actionForm_.getPage());
        }
        listRefine.setViewType(FRIENDS_TIMELINE);
        
        if (!protect) {
            if (formatType.isHtml()) {
                if (!shovelService.isMobilePhone()) {
                    page = listRefine.getPage();
                }
                since = null;
                limit = 0;
                
                if (home) {
                    temp = shovelService.getStatuses(user.getForeignKey(), true, page, limit, 0, 1);
                    statuses = shovelService.prepareForView(temp, limit, true);
                } else {
                    int correctedLimit = 0;
                    if (formatType.isHtml()) {
                        correctedLimit = 2;
                        status = shovelService.getRecent(user.getForeignKey());
                        request_.setAttribute("status", status);
                    }
                    statuses = shovelService.getStatuses(user.getForeignKey(), true, page, limit, 0, correctedLimit);
                    if (status == null) {
                        temp = statuses;
                    } else {
                        temp = (IStatus[])ArrayUtils.add(statuses, status);
                    }
                    shovelService.prepareForView(temp, limit, false);
                }
            } else {
                if (since == null || since.length() <= 0) {
                    since = request_.getHeader("If-Modified-Since");
                }
                if (since == null || since.length() <= 0) {
                    statuses = shovelService.getStatuses(user.getForeignKey(), true, page, limit, 0, 0);
                } else {
                    statuses = shovelService.getStatuses(user.getForeignKey(), true, since, limit);
                }
                shovelService.prepareForView(statuses, limit, false);
            }
        }
        request_.setAttribute("protect", protect);
        
        String forward = null;
        switch (formatType) {
        case HTML:
            if (shovelService.isMobilePhone()) {
                request_.setAttribute("at", actionForm_.getAt());
                request_.setAttribute("replyId", actionForm_.getReplyId());
                request_.setAttribute("page", page);
                forward = HOME_MOBILE;
            } else {
                //恐らくパスワードの再設定からの遷移
                String notification = (String)getSession().getAttribute(S_NOTIFICATION);
                getSession().removeAttribute(S_NOTIFICATION);
                if (notification != null) {
                    request_.setAttribute("notification", notification);
                }
                
                shovelService.prepareForView(user);
                request_.setAttribute("user", user);
                IFriendship[] friendships = shovelService.getFriends(user.getForeignKey(), 0, 100);
                request_.setAttribute("viewAllFriends", friendships.length > 100);
                friendships = shovelService.prepareForView(friendships, 100, true);
                request_.setAttribute("friendships", friendships);

                forward = actionForm_.isPartial() ? HOME_PARTIAL : HOME_FULL;
            }
            listRefine.setViewType(RECENT);
            boolean nextPage = false;
            if (statuses != null && statuses.length > 0) {
                nextPage = temp.length > statuses.length;
            }
            request_.setAttribute("nextPage", nextPage);
            break;
        case XML:
        case JSON:
            forward = formatType.getId();
            break;
        case ATOM:
        case RSS:
            shovelService.outputFeed(formatType, FRIENDS_TIMELINE, user, statuses);
            return null;
        default:
            throw new ApplicationException("");
        }
        request_.setAttribute("statuses", statuses);
        
        return forward;
    }
    
    public void setStatusesForm(IStatusesForm actionForm) {
        actionForm_ = actionForm;
    }
    public IShovelService getShovelService() {
        return (IShovelService)request_.getAttribute("shovelService");
    }
    public void setContainer(S2Container container) {
        container_ = container;
    }
    public void setRequest(HttpServletRequest request) {
        request_ = request;
    }
    public void setResponse(HttpServletResponse response) {
        response_ = response;
    }
    HttpSession getSession() {
        return request_.getSession(true);
    }
}
