/*
* 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.dao;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import jp.co.nemuzuka.common.TodoStatus;
import jp.co.nemuzuka.meta.TodoModelMeta;
import jp.co.nemuzuka.model.TodoModel;
import jp.co.nemuzuka.utils.CurrentDateUtils;
import jp.co.nemuzuka.utils.TagStringUtils;
import org.apache.commons.lang.StringUtils;
import org.slim3.datastore.Datastore;
import org.slim3.datastore.InMemoryFilterCriterion;
import org.slim3.datastore.InMemorySortCriterion;
import org.slim3.datastore.ModelMeta;
import org.slim3.datastore.ModelQuery;
import com.google.appengine.api.datastore.Key;
/**
* TodoModelに対するDao.
* @author kazumune
*/
public class TodoDao extends AbsDao {
/* (非 Javadoc)
* @see jp.co.nemuzuka.dao.AbsDao#getModelMeta()
*/
@SuppressWarnings("rawtypes")
@Override
ModelMeta getModelMeta() {
return TodoModelMeta.get();
}
/* (非 Javadoc)
* @see jp.co.nemuzuka.dao.AbsDao#getModelClass()
*/
@SuppressWarnings("rawtypes")
@Override
Class getModelClass() {
return TodoModel.class;
}
private static TodoDao todoDao = new TodoDao();
/**
* インスタンス取得.
* @return インスタンス
*/
public static TodoDao getInstance() {
return todoDao;
}
/**
* デフォルトコンストラクタ.
*/
private TodoDao() {}
/**
* List取得.
* @param param 検索条件
* @return 該当レコード
*/
public List<TodoModel> getList(Param param) {
TodoModelMeta e = (TodoModelMeta) getModelMeta();
if(StringUtils.isEmpty(param.targetMemberKeyString)) {
return new ArrayList<TodoModel>();
}
Set<InMemoryFilterCriterion> filterSet = new HashSet<InMemoryFilterCriterion>();
//ステータスの検索条件
String[] status = param.status;
if(status != null && status.length != 0) {
Set<TodoStatus> statusSet = new HashSet<TodoStatus>();
for(String statusCode : status) {
if(TodoStatus.NO_FINISH.equals(statusCode)) {
//未完了が選択された際には、未対応と対応中を検索条件に設定
statusSet.add(TodoStatus.nothing);
statusSet.add(TodoStatus.doing);
} else {
TodoStatus statusType = TodoStatus.fromCode(statusCode);
if(statusType != null) {
statusSet.add(statusType);
}
}
}
if(statusSet.size() != 0) {
filterSet.add(e.status.in(statusSet));
}
}
//件名の検索条件
if(StringUtils.isNotEmpty(param.title)) {
filterSet.add(e.title.startsWith(param.title));
}
boolean tagSearch = false;
String searchTagName = "";
//タグの検索条件
if(StringUtils.isNotEmpty(param.tag)) {
//ひとまず文字列の中間一致とする
filterSet.add(e.tag.contains(param.tag));
tagSearch = true;
searchTagName = param.tag;
}
//期限Fromの検索条件
if(param.fromPeriod != null) {
filterSet.add(e.period.isNotNull());
filterSet.add(e.period.greaterThanOrEqual(param.fromPeriod));
}
//期限Toの検索条件
if(param.toPeriod != null) {
filterSet.add(e.period.isNotNull());
filterSet.add(e.period.lessThanOrEqual(param.toPeriod));
}
//期限未設定のみを抽出
if(param.periodNull) {
//期限がnullであることを指定する
filterSet.add(e.period.equal(null));
}
Set<InMemorySortCriterion> sortSet = new LinkedHashSet<InMemorySortCriterion>();
if(param.orderByPeriod) {
//期限の昇順でソートする
sortSet.add(e.period.asc);
}
sortSet.add(e.key.asc);
//参照可能ユーザの検索条件
Key createMemberKey = Datastore.stringToKey(param.targetMemberKeyString);
filterSet.add(e.createMemberKey.equal(createMemberKey));
ModelQuery<TodoModel> query = Datastore.query(e).filterInMemory(filterSet.toArray(new InMemoryFilterCriterion[0]))
.sortInMemory(sortSet.toArray(new InMemorySortCriterion[0]));
List<TodoModel> retList = query.asList();
//検索条件にtagが指定されている場合、該当レコードのtagを分解し、完全一致のものだけ戻り値とする
//Datastoreへの問い合わせは、中間一致なので、設定値によっては、余計なものが取得される可能性がある為
if(tagSearch) {
List<TodoModel> list = new ArrayList<TodoModel>();
for(TodoModel target : retList) {
if(TagStringUtils.matchTag(target.getTag(), searchTagName)) {
list.add(target);
}
}
retList = list;
}
if(param.limit != null) {
int toIndex = param.limit;
if(toIndex > retList.size()) {
//結果が一覧取得数より少ない場合
toIndex = retList.size();
}
//一覧取得数の指定がされている場合、設定
return retList.subList(0, toIndex);
}
return retList;
}
/**
* ダッシュボード用一覧取得.
* ステータスが未完了のTODOを指定したlimit件数分取得します。
* 一覧は、
* ・期限が設定されているもの(期限の昇順)
* ・期限が未設定のもの(登録順)
* の順番でソートされます。
* @param limit 取得件数
* @param targetMemberKeyString 参照可能ユーザのKey文字列
* @return 該当レコード
*/
public List<TodoModel> getDashbordList(int limit, String targetMemberKeyString) {
//ステータスが未完了で、指定したLimit分取得する
//期限が設定されていて、未完了のものを取得
Param param = new Param();
param.status = new String[]{TodoStatus.NO_FINISH};
param.limit = limit;
param.targetMemberKeyString = targetMemberKeyString;
param.toPeriod = CurrentDateUtils.getInstance().getMaxDate();
param.orderByPeriod = true;
List<TodoModel> list = getList(param);
if(list.size() >= limit) {
//指定件数分取得できた場合、終了
return list;
}
//期限が設定されておらず、未完了のものを取得
param.toPeriod = null;
param.periodNull = true;
param.orderByPeriod = false;
List<TodoModel> periodNullList = getList(param);
for(TodoModel target : periodNullList) {
list.add(target);
if(list.size() >= limit) {
//追加後、上限件数を超えた場合、終了
break;
}
}
return list;
}
/**
* Model取得.
* @param key TodoModelのKey
* @param memberKey MemberModelのKey
* @return 存在すればModelインスタンス
*/
public TodoModel getWithMemberKey(Key key, Key memberKey) {
TodoModel model = get(key);
if(model != null) {
if(model.getCreateMemberKey().equals(memberKey) == false) {
model = null;
}
}
return model;
}
/**
* Model取得.
* @param key TodoModelのKey
* @param version TodoModelのバージョン
* @param memberKey MemberModelのKey
* @return 存在すればModelインスタンス
*/
public TodoModel get(Key key, Long version, Key memberKey) {
TodoModel model = get(key, version);
if(model != null) {
if(model.getCreateMemberKey().equals(memberKey) == false) {
model = null;
}
}
return model;
}
/**
* 検索条件パラメータ.
* @author k-katagiri
*/
public static class Param {
/** ステータス. */
public String[] status;
/** 件名. */
public String title;
/** タグ. */
public String tag;
/** 期限From. */
public Date fromPeriod;
/** 期限To. */
public Date toPeriod;
/** 期限がnullのもののみ取得する場合、true */
boolean periodNull;
/** 取得上限件数. */
public Integer limit;
/** MemberModelのKey文字列. */
public String targetMemberKeyString;
/** 期限の昇順でソートする場合、true */
boolean orderByPeriod;
}
}