OSDN Git Service

Merge branch 'release/v4.101.2'
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / data / Village.java
1 /*
2  * Village
3  *
4  * License : The MIT License
5  * Copyright(c) 2008 olyutorskii
6  */
7
8 package jp.sfjp.jindolf.data;
9
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Map;
15 import jp.sfjp.jindolf.view.AvatarPics;
16 import jp.sourceforge.jindolf.corelib.LandDef;
17 import jp.sourceforge.jindolf.corelib.VillageState;
18
19 /**
20  * いわゆる「村」。
21  */
22 public class Village{
23
24     private static final int GID_MIN = 3;
25
26
27     private final Land parentLand;
28     private final String villageID;
29     private final int villageIDNum;
30     private final String villageName;
31
32     private final boolean isValid;
33
34     private int limitMonth;
35     private int limitDay;
36     private int limitHour;
37     private int limitMinute;
38
39     private VillageState state = VillageState.UNKNOWN;
40
41     private final LinkedList<Period> periodList = new LinkedList<>();
42     private final List<Period> unmodList =
43             Collections.unmodifiableList(this.periodList);
44
45     private final Map<String, Avatar> avatarMap =
46             new HashMap<>();
47
48     private final AvatarPics avatarPics;
49
50     private boolean isLocalArchive = false;
51
52
53     /**
54      * Villageを生成する。
55      *
56      * @param parentLand Villageの所属する国
57      * @param villageID 村のID
58      * @param villageName 村の名前
59      */
60     public Village(Land parentLand, String villageID, String villageName) {
61         this.parentLand    = parentLand;
62         this.villageID   = villageID.intern();
63         this.villageIDNum = Integer.parseInt(this.villageID);
64         this.villageName = villageName.intern();
65
66         this.isValid = this.parentLand.getLandDef()
67                        .isValidVillageId(this.villageIDNum);
68
69         this.avatarPics = new AvatarPics(this.parentLand);
70
71         return;
72     }
73
74
75     /**
76      * 所属する国を返す。
77      *
78      * @return 村の所属する国(Land)
79      */
80     public Land getParentLand(){
81         return this.parentLand;
82     }
83
84     /**
85      * 村のID文字列を返す。
86      *
87      * @return 村ID
88      */
89     public String getVillageID(){
90         return this.villageID;
91     }
92
93     /**
94      * 村のID数値を返す。
95      *
96      * @return 村ID
97      */
98     public int getVillageIDNum(){
99         return this.villageIDNum;
100     }
101
102     /**
103      * 村の名前を返す。
104      *
105      * @return 村の名前
106      */
107     public String getVillageName(){
108         StringBuilder name = new StringBuilder();
109
110         LandDef landDef = this.parentLand.getLandDef();
111         String prefix = landDef.getLandPrefix();
112         name.append(prefix);
113
114         StringBuilder id = new StringBuilder(this.villageID);
115         if(landDef.getLandId().equals("wolfg")){
116             while(id.length() < GID_MIN){
117                 id.insert(0, '0');
118             }
119         }
120         name.append(id);
121
122         String result = name.toString();
123         return result;
124     }
125
126     /**
127      * 村の長い名前を返す。
128      *
129      * @return 村の長い名前
130      */
131     public String getVillageFullName(){
132         return this.villageName;
133     }
134
135     /**
136      * 村の状態を返す。
137      *
138      * @return 村の状態
139      */
140     public VillageState getState(){
141         return this.state;
142     }
143
144     /**
145      * 村の状態を設定する。
146      *
147      * @param state 村の状態
148      */
149     public void setState(VillageState state){
150         this.state = state;
151         return;
152     }
153
154     /**
155      * 日程及び更新時刻を持っているか判定する。
156      *
157      * @return 日程が不明ならtrue
158      */
159     public boolean hasSchedule(){
160         boolean result = ! this.periodList.isEmpty();
161         return result;
162     }
163
164     /**
165      * プロローグを返す。
166      *
167      * @return プロローグ
168      */
169     public Period getPrologue(){
170         for(Period period : this.periodList){
171             if(period.isPrologue()) return period;
172         }
173         return null;
174     }
175
176     /**
177      * エピローグを返す。
178      *
179      * @return エピローグ
180      */
181     public Period getEpilogue(){
182         for(Period period : this.periodList){
183             if(period.isEpilogue()) return period;
184         }
185         return null;
186     }
187
188     /**
189      * 指定された日付の進行日を返す。
190      *
191      * @param day 日付
192      * @return Period
193      */
194     public Period getProgress(int day){
195         for(Period period : this.periodList){
196             if(    period.isProgress()
197                 && period.getDay() == day ) return period;
198         }
199         return null;
200     }
201
202     /**
203      * PROGRESS状態のPeriodの総数を返す。
204      *
205      * @return PROGRESS状態のPeriod総数
206      */
207     public int getProgressDays(){
208         int result = 0;
209         for(Period period : this.periodList){
210             if(period.isProgress()) result++;
211         }
212         return result;
213     }
214
215     /**
216      * 指定されたPeriodインデックスのPeriodを返す。
217      *
218      * <p>プロローグやエピローグへのアクセスも可能。
219      *
220      * @param day Periodインデックス
221      * @return Period
222      */
223     public Period getPeriod(int day){
224         return this.periodList.get(day);
225     }
226
227     /**
228      * 指定されたアンカーの対象のPeriodを返す。
229      *
230      * @param anchor アンカー
231      * @return Period
232      */
233     public Period getPeriod(Anchor anchor){
234         Period anchorPeriod;
235
236         if(anchor.isEpilogueDay()){
237             anchorPeriod = getEpilogue();
238             return anchorPeriod;
239         }
240
241         int anchorDay = anchor.getDay();
242         anchorPeriod = getPeriod(anchorDay);
243
244         return anchorPeriod;
245     }
246
247     /**
248      * Period総数を返す。
249      *
250      * @return Period総数
251      */
252     public int getPeriodSize(){
253         return this.periodList.size();
254     }
255
256     /**
257      * Periodへのリストを返す。
258      *
259      * @return Periodのリスト。
260      */
261     public List<Period> getPeriodList(){
262         return this.unmodList;
263     }
264
265     /**
266      * 指定したフルネームで村に登録されているAvatarを返す。
267      *
268      * @param fullName Avatarの名前
269      * @return Avatar
270      */
271     public Avatar getAvatar(String fullName){
272         Avatar avatar = this.avatarMap.get(fullName);
273         return avatar;
274     }
275
276     /**
277      * Avatarを村に登録する。
278      *
279      * @param avatar Avatar
280      */
281     public void addAvatar(Avatar avatar){
282         if(avatar == null) return;
283
284         String fullName = avatar.getFullName();
285         if(this.avatarMap.get(fullName) != null) return;
286
287         this.avatarMap.put(fullName, avatar);
288         return;
289     }
290
291     /**
292      * Avatar画像管理を返す。
293      *
294      * @return 画像管理
295      */
296     public AvatarPics getAvatarPics(){
297         return this.avatarPics;
298     }
299
300     /**
301      * 村にアクセスするためのCGIクエリーを返す。
302      *
303      * @return CGIクエリー
304      */
305     public String getCGIQuery(){
306         StringBuilder result = new StringBuilder();
307         result.append("?vid=").append(getVillageID());
308         return result.toString();
309     }
310
311     /**
312      * 次回更新時を設定する。
313      *
314      * @param month 月
315      * @param day 日
316      * @param hour 時
317      * @param minute 分
318      */
319     public void setLimit(int month, int day, int hour, int minute){
320         this.limitMonth = month;
321         this.limitDay = day;
322         this.limitHour = hour;
323         this.limitMinute = minute;
324         return;
325     }
326
327     /**
328      * 次回更新月を返す。
329      *
330      * @return 更新月(1-12)
331      */
332     public int getLimitMonth(){
333         return this.limitMonth;
334     }
335
336     /**
337      * 次回更新日を返す。
338      *
339      * @return 更新日(1-31)
340      */
341     public int getLimitDay(){
342         return this.limitDay;
343     }
344
345     /**
346      * 次回更新時を返す。
347      *
348      * @return 更新時(0-23)
349      */
350     public int getLimitHour(){
351         return this.limitHour;
352     }
353
354     /**
355      * 次回更新分を返す。
356      *
357      * @return 更新分(0-59)
358      */
359     public int getLimitMinute(){
360         return this.limitMinute;
361     }
362
363     /**
364      * 有効な村か否か判定する。
365      *
366      * @return 無効な村ならfalse
367      */
368     public boolean isValid(){
369         return this.isValid;
370     }
371
372     /**
373      * Periodリストの指定したインデックスにPeriodを上書きする。
374      *
375      * <p>リストのサイズと同じインデックスを指定する事が許される。
376      * その場合の動作はList.addと同じ。
377      *
378      * @param index Periodリストのインデックス。
379      * @param period 上書きするPeriod
380      * @throws java.lang.IndexOutOfBoundsException インデックスの指定がおかしい
381      */
382     public void setPeriod(int index, Period period)
383             throws IndexOutOfBoundsException{
384         int listSize = this.periodList.size();
385         if(index == listSize){
386             this.periodList.add(period);
387         }else if(index < listSize){
388             this.periodList.set(index, period);
389         }else{
390             throw new IndexOutOfBoundsException();
391         }
392         return;
393     }
394
395     /**
396      * アンカーに一致する会話(Talk)のリストを取得する。
397      *
398      * @param anchor アンカー
399      * @return Talkのリスト
400      */
401     public List<Talk> getTalkListFromAnchor(Anchor anchor){
402         List<Talk> result = new LinkedList<>();
403
404         /* G国アンカー対応 */
405         if(anchor.hasTalkNo()){
406             // 事前に全Periodの全会話がロードされているのが前提
407             for(Period period : this.periodList){
408                 Talk talk = period.getNumberedTalk(anchor.getTalkNo());
409                 if(talk == null) continue;
410                 result.add(talk);
411             }
412             return result;
413         }
414
415         Period anchorPeriod = getPeriod(anchor);
416         if(anchorPeriod == null) return result;
417
418         // 事前にアンカー対象Periodの全会話がロードされているのが前提
419
420         for(Topic topic : anchorPeriod.getTopicList()){
421             if( ! (topic instanceof Talk) ) continue;
422             Talk talk = (Talk) topic;
423             if(talk.getHour()   != anchor.getHour()  ) continue;
424             if(talk.getMinute() != anchor.getMinute()) continue;
425             result.add(talk);
426         }
427         return result;
428     }
429
430     /**
431      * 全Periodの発言データをアンロードする。
432      */
433     public void unloadPeriods(){
434         for(Period period : this.periodList){
435             period.unload();
436         }
437         return;
438     }
439
440     /**
441      * この村がローカルなアーカイブに由来するものであるか判定する。
442      *
443      * @return ローカルなアーカイブによる村であればtrue
444      */
445     public boolean isLocalArchive(){
446         return this.isLocalArchive;
447     }
448
449     /**
450      * この村がローカルなアーカイブに由来するものであるか設定する。
451      *
452      * @param flag ローカルなアーカイブによる村であればtrue
453      */
454     public void setLocalArchive(boolean flag){
455         this.isLocalArchive = flag;
456         return;
457     }
458
459     /**
460      * {@inheritDoc}
461      *
462      * <p>村の文字列表現を返す。
463      * 村の名前と等しい。
464      *
465      * @return 村の名前
466      */
467     @Override
468     public String toString(){
469         return getVillageFullName();
470     }
471
472 }