001package csv2html;
002
003import java.awt.image.BufferedImage;
004import java.io.File;
005import java.lang.reflect.Constructor;
006import java.lang.reflect.InvocationTargetException;
007import java.util.ArrayList;
008import java.util.Calendar;
009import java.util.HashSet;
010import java.util.List;
011
012/**
013 * トランスレータ:CSVファイルをHTMLページへと変換するプログラム。
014 */
015public class Translator extends Object
016{
017        /**
018         * CSVに由来するテーブルを記憶するフィールド。
019         */
020        private Table inputTable;
021
022        /**
023         * HTMLに由来するテーブルを記憶するフィールド。
024         */
025        private Table outputTable;
026
027        /**
028         * 属性リストのクラスを指定したトランスレータのコンストラクタ。
029         * @param classOfAttributes 属性リストのクラス
030         */
031        public Translator(Class<? extends Attributes> classOfAttributes)
032        {
033                super();
034                Attributes.flushBaseDirectory();
035
036                try
037                {
038                        Constructor<? extends Attributes> aConstructor = classOfAttributes.getConstructor(String.class);
039
040                        this.inputTable = new Table(aConstructor.newInstance("input"));
041                        this.outputTable = new Table(aConstructor.newInstance("output"));
042                }
043                catch (NoSuchMethodException |
044                           InstantiationException |
045                           IllegalAccessException |
046                           InvocationTargetException anException) { anException.printStackTrace(); }
047
048                return;
049        }
050
051        /**
052         * 在位日数を計算して、それを文字列にして応答する。
053         * @param periodString 在位期間の文字列
054         * @return 在位日数の文字列
055         */     
056        public String computeNumberOfDays(String periodString)
057        {
058                String[] stringArray = periodString.split("[0-9]+", 0);   // 数字以外の文字列を得る(空文字列を含む)
059                HashSet<String> aSet = new HashSet<String>();
060                for (String aString : stringArray)   // 空文字列を除去しながらダブりも除く
061                {
062                        if (!aString.isEmpty()) { aSet.add(aString); }
063                }
064                StringBuffer aBuffer = new StringBuffer();   // 区切り記号の正規表現を作る
065                aBuffer.append('[');
066                boolean firstTime = true;
067                for (String aString : aSet)
068                {
069                        if (firstTime) { firstTime = false; }
070                        else { aBuffer.append('|'); }
071                        aBuffer.append(aString);
072                }
073                aBuffer.append(']');
074                String regularExpression = aBuffer.toString();
075                stringArray = periodString.split(regularExpression, 0);   // 日付の数字部分を取り出す(空文字列を含む)
076                List<String> aCollection = new ArrayList<String>();
077                for (String aString : stringArray)
078                {
079                        if (!aString.isEmpty()) { aCollection.add(aString); }   // 空文字列を除去
080                }
081
082                Calendar aCalendar = Calendar.getInstance();
083                int year = Integer.valueOf(aCollection.get(0));
084                int month = Integer.valueOf(aCollection.get(1)) - 1;
085                int day = Integer.valueOf(aCollection.get(2));
086                aCalendar.set(year, month, day);
087                long start = aCalendar.getTime().getTime();
088
089                aCalendar = Calendar.getInstance();
090                if (aCollection.size() > 3)
091                {
092                        year = Integer.valueOf(aCollection.get(3));
093                        month = Integer.valueOf(aCollection.get(4)) - 1;
094                        day = Integer.valueOf(aCollection.get(5));
095                        aCalendar.set(year, month, day);
096                }
097                long end = aCalendar.getTime().getTime();
098
099                long distance = ((end - start) / (1000 * 60 * 60 * 24)) + 1;
100
101                return String.format("%1$,d", distance);
102        }
103
104        /**
105         * サムネイル画像から画像へ飛ぶためのHTML文字列を作成して、それを応答する。
106         * @param aString 画像の文字列
107         * @param aTuple タプル
108         * @param no 番号
109         * @return サムネイル画像から画像へ飛ぶためのHTML文字列
110         */     
111        public String computeStringOfImage(String aString, Tuple aTuple, int no)
112        {
113                String noString = aTuple.values().get(aTuple.attributes().indexOfNo());
114                String thumbnailString = aTuple.values().get(aTuple.attributes().indexOfThumbnail());
115                BufferedImage thumbnailImage = this.inputTable.thumbnails().get(no);
116                int index = aTuple.attributes().indexOfThumbnail();
117                List<String> aCollection = IO.splitString(aTuple.values().get(index), "/");
118                index = aCollection.size() - 1;
119
120                StringBuffer aBuffer = new StringBuffer();
121                aBuffer.append("<a name=\"");
122                aBuffer.append(noString);
123                aBuffer.append("\" href=\"");
124                aBuffer.append(aString);
125                aBuffer.append("\">");
126                aBuffer.append("<img class=\"borderless\" src=\"");
127                aBuffer.append(thumbnailString);
128                aBuffer.append("\" width=\"");
129                aBuffer.append(thumbnailImage.getWidth());
130                aBuffer.append("\" height=\"");
131                aBuffer.append(thumbnailImage.getHeight());
132                aBuffer.append("\" alt=\"");
133                aBuffer.append(aCollection.get(index));
134                aBuffer.append("\"></a>");
135
136                return aBuffer.toString();
137        }
138
139        /**
140         * CSVファイルをHTMLページへ変換する。
141         */
142        public void execute()
143        {
144                // 必要な情報をダウンロードする。
145                Downloader aDownloader = new Downloader(this.inputTable);
146                aDownloader.perform();
147
148                // CSVに由来するテーブルをHTMLに由来するテーブルへと変換する。
149                System.out.println(this.inputTable);
150                this.translate();
151                System.out.println(this.outputTable);
152
153                // HTMLに由来するテーブルから書き出す。
154                Writer aWriter = new Writer(this.outputTable);
155                aWriter.perform();
156
157                // ブラウザを立ち上げて閲覧する。
158                try
159                {
160                        Attributes attributes = this.outputTable.attributes();
161                        String fileStringOfHTML = attributes.baseDirectory() + attributes.indexHTML();
162                        ProcessBuilder aProcessBuilder = new ProcessBuilder("open", "-a", "Safari", fileStringOfHTML);
163                        aProcessBuilder.start();
164                }
165                catch (Exception anException) { anException.printStackTrace(); }
166
167                return;
168        }
169
170        /**
171         * 属性リストのクラスを受け取って、CSVファイルをHTMLページへと変換するクラスメソッド。
172         * @param classOfAttributes 属性リストのクラス
173         */
174        public static void perform(Class<? extends Attributes> classOfAttributes)
175        {
176                // トランスレータのインスタンスを生成する。
177                Translator aTranslator = new Translator(classOfAttributes);
178                // トランスレータにCSVファイルをHTMLページへ変換するように依頼する。
179                aTranslator.execute();
180
181                return;
182        }
183
184        /**
185         * CSVファイルを基にしたテーブルから、HTMLページを基にするテーブルに変換する。
186         */
187        public void translate()
188        {
189                List<String> nameCollection = new ArrayList<String>();
190                int index = 0;
191                for (String aString : this.inputTable.attributes().names())
192                {
193                        if (index != this.inputTable.attributes().indexOfThumbnail())
194                        {
195                                nameCollection.add(IO.htmlCanonicalString(aString));
196
197                                if (index == this.inputTable.attributes().indexOfPeriod())
198                                {
199                                        nameCollection.add(IO.htmlCanonicalString("在位日数"));
200                                }
201                        }
202                        index++;
203                }
204                this.outputTable.attributes().names(nameCollection);
205
206                int no = 0;
207                for (Tuple aTuple : this.inputTable.tuples())
208                {
209                        List<String> valueCollection = new ArrayList<String>();
210                        index = 0;
211                        for (String aString : aTuple.values())
212                        {
213                                if (index != this.inputTable.attributes().indexOfThumbnail())
214                                {
215                                        if (index == this.inputTable.attributes().indexOfImage())
216                                        {
217                                                valueCollection.add(this.computeStringOfImage(aString, aTuple, no));
218                                        }
219                                        else
220                                        {
221                                                valueCollection.add(IO.htmlCanonicalString(aString));
222                                        }
223
224                                        if (index == this.inputTable.attributes().indexOfPeriod())
225                                        {
226                                                valueCollection.add(this.computeNumberOfDays(aString));
227                                        }
228                                }
229                                index++;
230                        }
231                        Tuple theTuple = new Tuple(this.outputTable.attributes(), valueCollection);
232                        this.outputTable.add(theTuple);
233                        no++;
234                }
235
236                return;
237        }
238}