OSDN Git Service

fce44ab26fe546ff3fc6604b16445dc6bc9bca23
[jindolf/JinArchiver.git] / src / main / java / jp / sourceforge / jindolf / archiver / VillageData.java
1 /*
2  * village data
3  *
4  * License : The MIT License
5  * Copyright(c) 2008 olyutorskii
6  */
7
8 package jp.sourceforge.jindolf.archiver;
9
10 import java.io.IOException;
11 import java.io.Writer;
12 import java.util.Collections;
13 import java.util.LinkedList;
14 import java.util.List;
15 import jp.sourceforge.jindolf.corelib.DisclosureType;
16 import jp.sourceforge.jindolf.corelib.LandDef;
17 import jp.sourceforge.jindolf.corelib.PeriodType;
18 import jp.sourceforge.jindolf.corelib.PreDefAvatar;
19
20 /**
21  * 村のデータモデル。
22  * villageタグに相当。
23  */
24 public class VillageData{
25
26     private final List<PeriodResource> resourceList;
27
28     private final LandDef landDef;
29     private final int villageId;
30     private final String baseUri;
31
32     private String fullName = "";
33     private int commitHour = -1;
34     private int commitMinute = -1;
35     private String graveIconUri;
36
37     private final List<AvatarData> avatarList = new LinkedList<>();
38     private int undefAvatarNo = 1;
39
40     private final List<PeriodData> periodList = new LinkedList<>();
41
42
43     /**
44      * コンストラクタ。
45      * @param resourceList PeriodResource並び
46      */
47     public VillageData(List<PeriodResource> resourceList){
48         super();
49
50         validatePeriodResource(resourceList);
51
52         this.resourceList = new LinkedList<>(resourceList);
53
54         PeriodResource resource1st = this.resourceList.get(0);
55         this.landDef   = resource1st.getLandDef();
56         this.villageId = resource1st.getVillageId();
57         this.baseUri = getBaseUri(this.resourceList);
58
59         return;
60     }
61
62
63     /**
64      * PeriodResourceの組が正当かチェックする。
65      * <ul>
66      * <li>全て同じ国に属していなければならない
67      * <li>全て同じ村に属していなければならない
68      * <li>日付は0から始まる連続した数値でなければならない
69      * <li>プロローグで始まらなければならない
70      * <li>エピローグで終わらなければならない
71      * <li>進行日はプロローグとエピローグに挟まれていなければならない
72      * </ul>
73      * @param list PeriodResource並び
74      * @throws IllegalArgumentException 引数が正当でない
75      */
76     public static void validatePeriodResource(List<PeriodResource> list)
77             throws IllegalArgumentException{
78         LandDef landDef = null;
79         int villageId = -1;
80         int lastDay = -1;
81         PeriodType periodType = null;
82
83         for(PeriodResource resource : list){
84             if(landDef == null){
85                 landDef = resource.getLandDef();
86             }else if(resource.getLandDef() != landDef){
87                 throw new IllegalArgumentException();
88             }
89
90             if(villageId < 0){
91                 villageId = resource.getVillageId();
92             }else if(resource.getVillageId() != villageId){
93                 throw new IllegalArgumentException();
94             }
95
96             if(lastDay < 0){
97                 lastDay = resource.getDay();
98                 if(lastDay != 0) throw new IllegalArgumentException();
99             }else{
100                 if(resource.getDay() != lastDay + 1){
101                     throw new IllegalArgumentException();
102                 }
103                 lastDay = resource.getDay();
104             }
105
106             if(periodType == null){
107                 periodType = resource.getPeriodType();
108                 if(periodType != PeriodType.PROLOGUE){
109                     throw new IllegalArgumentException();
110                 }
111                 if(lastDay != 0) throw new IllegalArgumentException();
112             }else if(periodType == PeriodType.PROLOGUE){
113                 periodType = resource.getPeriodType();
114                 if(periodType != PeriodType.PROGRESS){
115                     throw new IllegalArgumentException();
116                 }
117             }else if(periodType == PeriodType.PROGRESS){
118                 periodType = resource.getPeriodType();
119             }else if(periodType == PeriodType.EPILOGUE){
120                 throw new IllegalArgumentException();
121             }
122         }
123
124         if(lastDay < 0) throw new IllegalArgumentException();
125         if(periodType != PeriodType.EPILOGUE){
126             throw new IllegalArgumentException();
127         }
128
129         return;
130     }
131
132     /**
133      * 全PeriodResourceから、共通するベースURIを抽出する。
134      * @param list PeriodResource並び
135      * @return ベースURI文字列
136      * @throws IllegalArgumentException ベースURIが一致していない
137      */
138     public static String getBaseUri(List<PeriodResource> list)
139             throws IllegalArgumentException{
140         String result = null;
141
142         for(PeriodResource resource : list){
143             String urlText = resource.getOrigUrlText();
144             urlText = urlText.replaceAll("[^/]*$", "");
145             if(result == null){
146                 result = urlText;
147             }else{
148                 if( ! result.equals(urlText) ){
149                     throw new IllegalArgumentException();
150                 }
151             }
152         }
153
154         return result;
155     }
156
157     /**
158      * 国情報を取得する。
159      * @return 国情報
160      */
161     public LandDef getLandDef(){
162         return this.landDef;
163     }
164
165     /**
166      * 村IDを取得する。
167      * @return 村ID
168      */
169     public int getVillageId(){
170         return this.villageId;
171     }
172
173     /**
174      * ベースURIを取得する。
175      * @return ベースURI
176      */
177     public String getBaseUri(){
178         return this.baseUri;
179     }
180
181     /**
182      * 村フルネームを取得する。
183      * @return 村フルネーム
184      */
185     public String getFullName(){
186         return this.fullName;
187     }
188
189     /**
190      * 村フルネームを設定する。
191      * @param fullName 村フルネーム
192      */
193     public void setFullName(String fullName){
194         this.fullName = fullName;
195         return;
196     }
197
198     /**
199      * 更新時を取得する。
200      * @return 更新時
201      */
202     public int getCommitHour(){
203         return this.commitHour;
204     }
205
206     /**
207      * 更新時を設定する。
208      * @param commitHour 更新時
209      */
210     public void setCommitHour(int commitHour){
211         this.commitHour = commitHour;
212         return;
213     }
214
215     /**
216      * 更新分を取得する。
217      * @return 更新分
218      */
219     public int getCommitMinute(){
220         return this.commitMinute;
221     }
222
223     /**
224      * 更新分を設定する。
225      * @param commitMinute 更新分
226      */
227     public void setCommitMinute(int commitMinute){
228         this.commitMinute = commitMinute;
229         return;
230     }
231
232     /**
233      * 墓アイコンURIを取得する。
234      * @return 墓アイコンURI文字列
235      */
236     public String getGraveIconUri(){
237         if(this.graveIconUri == null){
238             return this.landDef.getTombFaceIconURI().toASCIIString();
239         }
240         return this.graveIconUri;
241     }
242
243     /**
244      * 墓アイコンURI文字列を設定する。
245      * @param graveIconUri 墓アイコンURI文字列
246      */
247     public void setGraveIconUri(String graveIconUri){
248         this.graveIconUri = graveIconUri;
249         return;
250     }
251
252     /**
253      * 全Periodの開示状況から総合開示状況を算出する。
254      * @return 公開状況
255      */
256     public DisclosureType getDisclosureType(){
257         DisclosureType result = DisclosureType.COMPLETE;
258
259         for(PeriodData period : this.periodList){
260             DisclosureType type = period.getDisclosureType();
261             switch(type){
262             case HOT:
263                 return DisclosureType.HOT;
264             case UNCOMPLETE:
265                 result = DisclosureType.UNCOMPLETE;
266                 break;
267             default:
268                 break;
269             }
270         }
271
272         return result;
273     }
274
275     /**
276      * Periodモデルを追加する。
277      * @param period Periodモデル
278      */
279     public void addPeriodData(PeriodData period){
280         this.periodList.add(period);
281         return;
282     }
283
284     /**
285      * PeriodResourcenar並びを取得する。
286      * @return PeriodResource並び
287      */
288     public List<PeriodResource> getPeriodResourceList(){
289         return Collections.unmodifiableList(this.resourceList);
290     }
291
292     /**
293      * 未知の新規Avatarを生成する。
294      * ※ F1556村などへの対処。
295      * Avatarのフルネーム、短縮名、識別子が設定される。
296      * @param avfullName Avatarのフルネーム
297      * @return 新規Avatarモデル
298      */
299     public AvatarData createAvatar(String avfullName){
300         AvatarData avatar = new AvatarData();
301
302         avatar.setFullName(avfullName);
303
304         String[] token = avfullName.split("\\s");
305         String shortName = token[token.length - 1];
306         avatar.setShortName(shortName);
307
308         String avatarId = "ukavatar" + this.undefAvatarNo;
309         this.undefAvatarNo++;
310         avatar.setAvatarId(avatarId);
311
312         return avatar;
313     }
314
315     /**
316      * AvatarフルネームからAvatarを得る。
317      * まだこの村にいないAvatarならAvatar一覧に登録される。
318      * @param seq Avatarフルネーム
319      * @return Avatarモデル
320      */
321     public AvatarData getAvatarData(CharSequence seq){
322         for(AvatarData avatar : this.avatarList){
323             String avfullName = avatar.getFullName();
324             if(avfullName.contentEquals(seq)){
325                 return avatar;
326             }
327         }
328
329         PreDefAvatar predefAvatar =
330                 AvatarData.getPreDefAvatar(seq);
331         if(predefAvatar != null){
332             AvatarData avatar = new AvatarData(predefAvatar);
333             this.avatarList.add(avatar);
334             return avatar;
335         }
336
337         AvatarData avatar = createAvatar(seq.toString());
338         this.avatarList.add(avatar);
339
340         return avatar;
341     }
342
343     /**
344      * avatarList要素のXML出力。
345      * @param writer 出力先
346      * @throws IOException 出力エラー
347      */
348     public void dumpAvatarList(Writer writer) throws IOException{
349         writer.append("<avatarList>").append("\n\n");
350
351         for(AvatarData avatar : this.avatarList){
352             avatar.dumpXml(writer);
353             writer.append('\n');
354         }
355
356         writer.append("</avatarList>").append('\n');
357
358         return;
359     }
360
361     /**
362      * 全period要素のXML出力。
363      * @param writer 出力先
364      * @throws IOException 出力エラー
365      */
366     public void dumpPeriodList(Writer writer) throws IOException{
367         for(PeriodData period : this.periodList){
368             period.dumpXml(writer);
369             writer.append('\n');
370         }
371         return;
372     }
373
374     /**
375      * village要素のXML出力。
376      * @param writer 出力先
377      * @throws IOException 出力エラー
378      */
379     public void dumpXml(Writer writer) throws IOException{
380         writer.append("<village\n");
381
382         XmlUtils.indent(writer, 1);
383         XmlUtils.dumpNameSpaceDecl(writer);
384         writer.append('\n');
385
386         XmlUtils.indent(writer, 1);
387         XmlUtils.dumpSiNameSpaceDecl(writer);
388         writer.append('\n');
389
390         XmlUtils.indent(writer, 1);
391         XmlUtils.dumpSchemeLocation(writer);
392         writer.append('\n');
393
394         XmlUtils.indent(writer, 1);
395         XmlUtils.attrOut(writer, "xml:lang", "ja-JP");
396         writer.append('\n');
397
398         XmlUtils.indent(writer, 1);
399         XmlUtils.attrOut(writer, "xml:base", this.baseUri);
400         writer.append('\n');
401
402         XmlUtils.indent(writer, 1);
403         XmlUtils.attrOut(writer, "fullName", this.fullName);
404
405         writer.append(' ');
406         XmlUtils.attrOut(writer, "vid", Integer.toString(this.villageId));
407         writer.append('\n');
408
409         XmlUtils.indent(writer, 1);
410         XmlUtils.timeAttrOut(writer,
411                              "commitTime",
412                              this.commitHour, this.commitMinute);
413         writer.append('\n');
414
415         XmlUtils.indent(writer, 1);
416         XmlUtils.attrOut(writer, "state", "gameover");
417
418         DisclosureType type = getDisclosureType();
419         if(type != DisclosureType.COMPLETE){
420             writer.append(' ');
421             XmlUtils.attrOut(writer, "disclosure", type.getXmlName());
422         }
423
424         String isValid;
425         if(this.landDef.isValidVillageId(this.villageId)){
426             isValid = "true";
427         }else{
428             isValid = "false";
429         }
430         writer.append(' ');
431         XmlUtils.attrOut(writer, "isValid", isValid);
432         writer.append('\n');
433
434         XmlUtils.indent(writer, 1);
435         XmlUtils.attrOut(writer, "landName", this.landDef.getLandName());
436
437         writer.append(' ');
438         XmlUtils.attrOut(writer, "formalName", this.landDef.getFormalName());
439         writer.append('\n');
440
441         XmlUtils.indent(writer, 1);
442         XmlUtils.attrOut(writer, "landId", this.landDef.getLandId());
443
444         writer.append(' ');
445         XmlUtils.attrOut(writer, "landPrefix", this.landDef.getLandPrefix());
446         writer.append('\n');
447
448         XmlUtils.indent(writer, 1);
449         String locale = this.landDef.getLocale().toString();
450         locale = locale.replaceAll("_", "-");
451         XmlUtils.attrOut(writer, "locale", locale);
452
453         writer.append(' ');
454         XmlUtils.attrOut(writer,
455                 "origencoding", this.landDef.getEncoding().name());
456
457         writer.append(' ');
458         XmlUtils.attrOut(writer,
459                 "timezone", this.landDef.getTimeZone().getID());
460         writer.append('\n');
461
462         XmlUtils.indent(writer, 1);
463         XmlUtils.attrOut(writer, "graveIconURI", getGraveIconUri());
464         writer.append('\n');
465
466         XmlUtils.indent(writer, 1);
467         XmlUtils.attrOut(writer, "generator", JinArchiver.GENERATOR);
468         writer.append('\n');
469
470         writer.append(">").append('\n');
471
472         writer.append('\n');
473         dumpAvatarList(writer);
474
475         writer.append('\n');
476         dumpPeriodList(writer);
477
478         writer.append("</village>").append("\n");
479
480         return;
481     }
482
483 }