OSDN Git Service

decode talk only in XML.
[jindolf/Jindolf.git] / src / main / java / jp / sfjp / jindolf / data / xml / VillageHandler.java
index 4e67d01..cb320cc 100644 (file)
@@ -7,7 +7,17 @@
 
 package jp.sfjp.jindolf.data.xml;
 
+import java.util.HashMap;
+import java.util.Map;
+import jp.sfjp.jindolf.data.Avatar;
+import jp.sfjp.jindolf.data.CoreData;
+import jp.sfjp.jindolf.data.Land;
+import jp.sfjp.jindolf.data.Period;
+import jp.sfjp.jindolf.data.Talk;
 import jp.sfjp.jindolf.data.Village;
+import jp.sourceforge.jindolf.corelib.PeriodType;
+import jp.sourceforge.jindolf.corelib.TalkType;
+import jp.sourceforge.jindolf.corelib.VillageState;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.Locator;
@@ -15,9 +25,43 @@ import org.xml.sax.SAXException;
 
 /**
  * VillageのXMLパーサ本体。
+ *
+ * <p>パース中の各種コンテキストを保持する。
  */
 public class VillageHandler implements ContentHandler{
 
+    private static final String NS_JINARCHIVE =
+            "http://jindolf.sourceforge.jp/xml/ns/501";
+
+    private static final Map<String, PeriodType> periodTypeMap =
+            new HashMap<>();
+
+    static{
+        periodTypeMap.put("prologue", PeriodType.PROLOGUE);
+        periodTypeMap.put("progress", PeriodType.PROGRESS);
+        periodTypeMap.put("epilogue", PeriodType.EPILOGUE);
+    }
+
+
+    private String nsPfx;
+
+    private Land land;
+    private Village village;
+    private Period period;
+
+    private Avatar talkAvatar;
+    private int talkNo;
+
+    private TalkType talkType;
+    private String messageId;
+    private String talkTime;
+
+    private boolean inLine;
+    private final StringBuilder content = new StringBuilder(250);
+
+    private final Map<String, Avatar> idAvatarMap = new HashMap<>();
+
+
     /**
      * constructor.
      */
@@ -28,12 +72,202 @@ public class VillageHandler implements ContentHandler{
 
 
     /**
+     * 会話種別をデコードする。
+     *
+     * @param type 属性値
+     * @return 会話種別
+     */
+    private static TalkType decodeTalkType(String type){
+        TalkType result;
+
+        switch(type){
+            case "public":
+                result = TalkType.PUBLIC;
+                break;
+            case "wolf":
+                result = TalkType.WOLFONLY;
+                break;
+            case "private":
+                result = TalkType.PRIVATE;
+                break;
+            case "grave":
+                result = TalkType.GRAVE;
+                break;
+            default:
+                assert false;
+                throw new AssertionError();
+        }
+
+        return result;
+    }
+
+
+    /**
      * パースした結果のVillageを返す。
      *
-     * @return 村
+     * @return 村
      */
     public Village getVillage(){
-        return null;
+        return this.village;
+    }
+
+    /**
+     * パース開始前の準備。
+     */
+    private void resetBefore(){
+        this.idAvatarMap.clear();
+        this.content.setLength(0);
+        this.inLine = false;
+        return;
+    }
+
+    /**
+     * パース開始後の後始末。
+     */
+    private void resetAfter(){
+        this.idAvatarMap.clear();
+        this.content.setLength(0);
+        this.nsPfx = null;
+        this.land = null;
+        this.period = null;
+        this.messageId = null;
+        this.talkTime = null;
+        return;
+    }
+
+    /**
+     * village要素開始の受信。
+     *
+     * @param atts 属性
+     */
+    private void startVillage(Attributes atts){
+        String landId = atts.getValue("", "landId");
+        String vid    = atts.getValue("", "vid");
+        String name   = atts.getValue("", "fullName");
+        String state  = atts.getValue("", "state");
+
+        this.land = CoreData.getLandDefList().stream()
+                .filter(landDef -> landDef.getLandId().equals(landId))
+                .map(landDef -> new Land(landDef))
+                .findFirst().get();
+
+        this.village = new Village(this.land, vid, name);
+        this.village.setState(VillageState.GAMEOVER);
+        this.talkNo = 0;
+        return;
+    }
+
+    /**
+     * avatar要素開始の受信。
+     *
+     * @param atts 属性
+     */
+    private void startAvatar(Attributes atts){
+        String avatarId = atts.getValue("", "avatarId");
+        String fullName = atts.getValue("", "fullName");
+        String shortName = atts.getValue("", "shortName");
+        String faceIconUri = atts.getValue("", "faceIconURI");
+
+        Avatar avatar = Avatar.getPredefinedAvatar(fullName);
+
+        this.village.addAvatar(avatar);
+        this.idAvatarMap.put(avatarId, avatar);
+
+        System.out.println(avatar);
+
+        return;
+    }
+
+    /**
+     * period要素開始の受信。
+     *
+     * @param atts 属性
+     */
+    private void startPeriod(Attributes atts){
+        String typeAttr = atts.getValue("", "type");
+        String dayAttr = atts.getValue("", "day");
+
+        PeriodType periodType = periodTypeMap.get(typeAttr);
+        int day = Integer.parseInt(dayAttr);
+
+        this.period = new Period(this.village, periodType, day);
+        int periodIdx = this.village.getPeriodSize();
+        this.village.setPeriod(periodIdx, this.period);
+
+        return;
+    }
+
+    /**
+     * talk要素開始の受信。
+     *
+     * @param atts 属性
+     */
+    private void startTalk(Attributes atts){
+        String type = atts.getValue("", "type");
+        String avatarId = atts.getValue("", "avatarId");
+        String xname = atts.getValue("", "xname");
+        String time = atts.getValue("", "time");
+        this.talkAvatar = this.idAvatarMap.get(avatarId);
+        this.talkType = decodeTalkType(type);
+        this.messageId = xname;
+        this.content.setLength(0);
+        this.talkTime = time;
+    }
+
+    /**
+     * talk要素終了の受信。
+     */
+    private void endTalk(){
+        int no = 0;
+        if(this.talkType == TalkType.PUBLIC){
+            no = this.talkNo++;
+        }
+
+        int d0;
+        int d1;
+        d1 = this.talkTime.charAt(0) - '0';
+        d0 = this.talkTime.charAt(1) - '0';
+        int hour = d1 * 10 + d0;
+        d1 = this.talkTime.charAt(3) - '0';
+        d0 = this.talkTime.charAt(4) - '0';
+        int minute = d1 * 10 + d0;
+
+        Talk talk = new Talk(
+                this.period,
+                this.talkType, this.talkAvatar,
+                no, this.messageId,
+                hour, minute,
+                this.content.toString()
+        );
+
+        this.period.addTopic(talk);
+
+        this.talkType = null;
+        this.talkAvatar = null;
+        this.messageId = null;
+        this.content.setLength(0);
+        this.talkTime = null;
+    }
+
+    /**
+     * li要素開始の受信。
+     *
+     * @param atts 属性
+     */
+    private void startLi(Attributes atts){
+        this.inLine = true;
+        if(this.content.length() > 0){
+            this.content.append('\n');
+        }
+        return;
+    }
+
+    /**
+     * li要素終了の受信。
+     */
+    private void endLi(){
+        this.inLine = false;
+        return;
     }
 
     /**
@@ -53,6 +287,7 @@ public class VillageHandler implements ContentHandler{
      */
     @Override
     public void startDocument() throws SAXException {
+        resetBefore();
         return;
     }
 
@@ -63,6 +298,7 @@ public class VillageHandler implements ContentHandler{
      */
     @Override
     public void endDocument() throws SAXException {
+        resetAfter();
         return;
     }
 
@@ -76,8 +312,9 @@ public class VillageHandler implements ContentHandler{
     @Override
     public void startPrefixMapping(String prefix, String uri)
             throws SAXException {
-        //System.out.println(prefix);
-        //System.out.println(uri);
+        if(NS_JINARCHIVE.equals(uri)){
+            this.nsPfx = prefix;
+        }
         return;
     }
 
@@ -108,9 +345,30 @@ public class VillageHandler implements ContentHandler{
                              String qName,
                              Attributes atts)
             throws SAXException {
-        //System.out.println(uri);
-        //System.out.println(localName);
-        //System.out.println(qName);
+        if( ! NS_JINARCHIVE.equals(uri)){
+            return;
+        }
+
+        switch(localName){
+            case "village":
+                startVillage(atts);
+                break;
+            case "avatar":
+                startAvatar(atts);
+                break;
+            case "period":
+                startPeriod(atts);
+                break;
+            case "talk":
+                startTalk(atts);
+                break;
+            case "li":
+                startLi(atts);
+                break;
+            default:
+                break;
+        }
+
         return;
     }
 
@@ -125,6 +383,20 @@ public class VillageHandler implements ContentHandler{
     @Override
     public void endElement(String uri, String localName, String qName)
             throws SAXException {
+        if( ! NS_JINARCHIVE.equals(uri)){
+            return;
+        }
+        switch(localName){
+            case "talk":
+                endTalk();
+                break;
+            case "li":
+                endLi();
+                break;
+            default:
+                break;
+        }
+
         return;
     }
 
@@ -139,6 +411,8 @@ public class VillageHandler implements ContentHandler{
     @Override
     public void characters(char[] ch, int start, int length)
             throws SAXException {
+        if(!this.inLine) return;
+        this.content.append(ch, start, length);
         return;
     }