/*
* Copyright 2012 Kazumune Katagiri. (http://d.hatena.ne.jp/nemuzuka)
*
* Licensed 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.
*/
package jp.co.nemuzuka.service.impl;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slim3.datastore.Datastore;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Text;
import jp.co.nemuzuka.common.PeriodStatus;
import jp.co.nemuzuka.common.TodoStatus;
import jp.co.nemuzuka.dao.TodoDao;
import jp.co.nemuzuka.dao.TodoDao.Param;
import jp.co.nemuzuka.entity.TodoModelEx;
import jp.co.nemuzuka.form.TodoCommentForm;
import jp.co.nemuzuka.form.TodoDetailForm;
import jp.co.nemuzuka.form.TodoForm;
import jp.co.nemuzuka.model.TodoModel;
import jp.co.nemuzuka.service.CommentService;
import jp.co.nemuzuka.service.MemberService;
import jp.co.nemuzuka.service.TodoService;
import jp.co.nemuzuka.service.TodoTagService;
import jp.co.nemuzuka.utils.ConvertUtils;
import jp.co.nemuzuka.utils.CurrentDateUtils;
import jp.co.nemuzuka.utils.DateTimeUtils;
/**
* TodoServiceの実装クラス.
* @author k-katagiri
*/
public class TodoServiceImpl implements TodoService {
TodoDao todoDao = TodoDao.getInstance();
CommentService commentService = CommentServiceImpl.getInstance();
MemberService memberService = MemberServiceImpl.getInstance();
TodoTagService todoTagService = TodoTagServiceImpl.getInstance();
private static TodoServiceImpl impl = new TodoServiceImpl();
/**
* インスタンス取得.
* @return インスタンス
*/
public static TodoServiceImpl getInstance() {
return impl;
}
/**
* デフォルトコンストラクタ.
*/
private TodoServiceImpl(){}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#getList(jp.co.nemuzuka.dao.TodoDao.Param)
*/
@Override
public List<TodoModelEx> getList(Param param, boolean isDashboard) {
List<TodoModel> modelList = null;
if(isDashboard) {
modelList = todoDao.getDashbordList(param.limit, param.targetMemberKeyString);
} else {
modelList = todoDao.getList(param);
}
List<TodoModelEx> list = new ArrayList<TodoModelEx>();
Date today = CurrentDateUtils.getInstance().getCurrentDate();
SimpleDateFormat sdf = DateTimeUtils.createSdf("yyyyMMdd");
SimpleDateFormat sdf2 = DateTimeUtils.createSdf("yyyy/MM/dd HH:mm");
for(TodoModel target : modelList) {
TodoModelEx entity = new TodoModelEx();
entity.setModel(target);
entity.setPeriod(ConvertUtils.toString(target.getPeriod(), sdf));
entity.setCreatedAt(ConvertUtils.toString(target.getCreatedAt(), sdf2));
//期限が設定されている場合
if(target.getPeriod() != null) {
entity.setPeriodStatus(
createPeriodStatus(today, target.getPeriod(), target.getStatus()));
}
entity.setTodoStatus(target.getStatus().getLabel());
list.add(entity);
}
return list;
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#get(java.lang.String, java.lang.String)
*/
@Override
public TodoForm get(String keyString, String mail) {
TodoForm form = new TodoForm();
if(StringUtils.isNotEmpty(keyString)) {
//Key情報が設定されていた場合
Key key = Datastore.stringToKey(keyString);
Key memberKey = memberService.getKey(mail);
TodoModel model = todoDao.getWithMemberKey(key, memberKey);
setForm(form, model);
}
//TODOタグ一覧を設定
form.setTagList(todoTagService.getList(mail));
return form;
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#getDetail(java.lang.String, java.lang.String)
*/
@Override
public TodoDetailForm getDetail(String keyString, String mail) {
TodoForm form = get(keyString, mail);
if(StringUtils.isEmpty(form.keyToString)) {
return null;
}
TodoDetailForm detailForm = new TodoDetailForm();
detailForm.setForm(form);
detailForm.commentList = commentService.getList(Datastore.stringToKey(form.keyToString));
return detailForm;
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#updateTodoStatus(jp.co.nemuzuka.form.TodoForm, java.lang.String)
*/
@Override
public void updateTodoStatus(TodoForm form, String email) {
TodoModel model = null;
Key memberKey = memberService.getKey(email);
Key key = Datastore.stringToKey(form.keyToString);
Long version = ConvertUtils.toLong(form.versionNo);
//keyとバージョンとメンバーKeyでデータを取得
model = todoDao.get(key, version, memberKey);
if(model == null) {
//該当レコードが存在しない場合、Exceptionをthrow
throw new ConcurrentModificationException();
}
TodoStatus status = TodoStatus.fromCode(form.todoStatus);
if(status == null) {
status = TodoStatus.nothing;
}
model.setStatus(status);
todoDao.put(model);
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#put(jp.co.nemuzuka.form.TodoForm, java.lang.String)
*/
@Override
public void put(TodoForm form, String mail) {
TodoModel model = null;
Key memberKey = memberService.getKey(mail);
if(StringUtils.isNotEmpty(form.keyToString)) {
//更新の場合
Key key = Datastore.stringToKey(form.keyToString);
Long version = ConvertUtils.toLong(form.versionNo);
//keyとバージョンとメンバーKeyでデータを取得
model = todoDao.get(key, version, memberKey);
if(model == null) {
//該当レコードが存在しない場合、Exceptionをthrow
throw new ConcurrentModificationException();
}
} else {
//登録者の情報として設定
model = new TodoModel();
model.setCreateMemberKey(memberKey);
}
//取得した情報に対してプロパティを更新
setModel(model, form);
todoDao.put(model);
//登録されたTODOタグをマスタ登録
putTodoTag(form.tag, mail);
}
/**
* TODOタグ登録.
* 引数の情報を元に、TODOタグを登録します。
* @param tag 入力タグ値(カンマ区切りで複数登録)
* @param mail メールアドレス
*/
private void putTodoTag(String tag, String mail) {
if(StringUtils.isEmpty(tag)) {
return;
}
String[] tags = tag.split(",");
Set<String> tagSet = new LinkedHashSet<String>();
for(String target : tags) {
String tagName = StringUtils.trimToEmpty(target);
if(StringUtils.isEmpty(tagName)) {
continue;
}
tagSet.add(tagName);
}
if(tagSet.size() == 0) {
return;
}
todoTagService.put(tagSet.toArray(new String[0]), mail);
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#delete(jp.co.nemuzuka.form.TodoForm, java.lang.String)
*/
@Override
public void delete(TodoForm form, String mail) {
Key key = Datastore.stringToKey(form.keyToString);
Key memberKey = memberService.getKey(mail);
Long version = ConvertUtils.toLong(form.versionNo);
//keyとバージョンとメンバーKeyでデータを取得
TodoModel model = todoDao.get(key, version, memberKey);
if(model == null) {
//該当レコードが存在しない場合、Exceptionをthrow
throw new ConcurrentModificationException();
}
todoDao.delete(key);
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#putComment(jp.co.nemuzuka.form.TodoCommentForm, java.lang.String)
*/
@Override
public void putComment(TodoCommentForm form, String email) {
//ステータスが変更されていないかチェックする
Key todoModelKey = Datastore.stringToKey(form.keyToString);
Key memberKey = memberService.getKey(email);
//KeyとメンバーKeyでデータを取得
TodoModel model = todoDao.getWithMemberKey(todoModelKey, memberKey);
if(model == null) {
//該当レコードが存在しない場合、Exceptionをthrow
throw new ConcurrentModificationException();
}
//ステータスが変更されているかチェックする
TodoStatus status = TodoStatus.fromCode(form.status);
if(status == null) {
status = TodoStatus.nothing;
}
if(model.getStatus().equals(status) == false) {
Long versonNo = ConvertUtils.toLong(form.versionNo);
//変更されているので、更新
if(model.getVersion().equals(versonNo) == false) {
//他のユーザに更新されている可能性があるので、Exceptionをthrow
throw new ConcurrentModificationException();
}
model.setStatus(status);
todoDao.put(model);
}
//コメント登録
commentService.put(todoModelKey, form.comment, email);
}
/* (non-Javadoc)
* @see jp.co.nemuzuka.service.TodoService#deleteComment(java.lang.String, java.lang.String, java.lang.Long, java.lang.String)
*/
@Override
public void deleteComment(String keyString, String commentKeyString,
Long commentVersionNo, String email) {
//TODOの存在チェック
Key todoModelKey = Datastore.stringToKey(keyString);
Key memberKey = memberService.getKey(email);
//KeyとメンバーKeyでデータを取得
TodoModel model = todoDao.getWithMemberKey(todoModelKey, memberKey);
if(model == null) {
//該当レコードが存在しない場合、Exceptionをthrow
throw new ConcurrentModificationException();
}
//コメント削除
commentService.delete(todoModelKey, commentKeyString, commentVersionNo);
}
/**
* 期限ステータス判断.
* @param today システム日付
* @param targetDate 期限
* @param todoStatus TODOステータス
* @return 期限ステータス
*/
PeriodStatus createPeriodStatus(Date today, Date targetDate, TodoStatus todoStatus) {
long toDayTime = today.getTime();
long periodTime = targetDate.getTime();
//ステータスが未完了の場合
PeriodStatus periodStatus = null;
switch(todoStatus) {
case doing:case nothing:
if(toDayTime == periodTime) {
periodStatus = PeriodStatus.today;
} else if(toDayTime > periodTime) {
periodStatus = PeriodStatus.periodDate;
}
break;
}
return periodStatus;
}
/**
* Form情報設定.
* @param form 設定対象Form
* @param model 設定Model
*/
private void setForm(TodoForm form, TodoModel model) {
if(model == null) {
return;
}
SimpleDateFormat sdf = DateTimeUtils.createSdf("yyyyMMdd");
form.keyToString = model.getKeyToString();
form.todoStatus = model.getStatus().getCode();
form.title = model.getTitle();
form.tag = StringUtils.defaultString(model.getTag());
form.content = model.getContent().getValue();
form.period = ConvertUtils.toString(model.getPeriod(), sdf);
form.versionNo = ConvertUtils.toString(model.getVersion());
}
/**
* Model情報設定.
* @param model 設定対象Model
* @param form 設定Form
*/
private void setModel(TodoModel model, TodoForm form) {
SimpleDateFormat sdf = DateTimeUtils.createSdf("yyyyMMdd");
TodoStatus status = TodoStatus.fromCode(form.todoStatus);
if(status == null) {
status = TodoStatus.nothing;
}
model.setStatus(status);
model.setTitle(form.title);
model.setTag(reCreateTag(form.tag));
model.setContent(new Text(StringUtils.defaultString(form.content)));
model.setPeriod(ConvertUtils.toDate(form.period, sdf));
model.setVersion(ConvertUtils.toLong(form.versionNo));
}
/**
* Tag情報再設定.
* 引数のTag情報を成型します。
* @param tag Tag情報
* @return 成型後Tag
*/
private String reCreateTag(String tag) {
if(StringUtils.isEmpty(tag)) {
return "";
}
String[] array = ConvertUtils.toStringArray(tag, ",");
StringBuilder sb = new StringBuilder();
for(String target : array) {
if(sb.length() != 0) {
sb.append(",");
}
sb.append(target);
}
return sb.toString();
}
}