1 | package org.farng.mp3.filename; |
2 | |
3 | import org.farng.mp3.AbstractMP3Tag; |
4 | import org.farng.mp3.TagOptionSingleton; |
5 | import org.farng.mp3.id3.AbstractFrameBodyTextInformation; |
6 | import org.farng.mp3.id3.AbstractFrameBodyUrlLink; |
7 | import org.farng.mp3.id3.AbstractID3v2Frame; |
8 | import org.farng.mp3.id3.AbstractID3v2FrameBody; |
9 | import org.farng.mp3.id3.FrameBodyCOMM; |
10 | import org.farng.mp3.id3.ID3v2_4; |
11 | import org.farng.mp3.id3.ID3v2_4Frame; |
12 | |
13 | import java.util.Iterator; |
14 | |
15 | /** |
16 | * This composite subclass is the leaf of the tree. It contains the actual strings found in the filename. |
17 | * |
18 | * @author Eric Farng |
19 | * @version $Revision: 1.7 $ |
20 | */ |
21 | public class FilenameToken extends AbstractFilenameComposite { |
22 | |
23 | /** |
24 | * what information this object represents. |
25 | */ |
26 | private Class id3v2FrameBodyClass = null; |
27 | /** |
28 | * token that this object represents |
29 | */ |
30 | private String token = null; |
31 | |
32 | /** |
33 | * Creates a new FilenameToken object. |
34 | */ |
35 | public FilenameToken() { |
36 | super(); |
37 | } |
38 | |
39 | /** |
40 | * Creates a new FilenameToken object. |
41 | */ |
42 | public FilenameToken(final FilenameToken copyObject) { |
43 | super(copyObject); |
44 | try { |
45 | id3v2FrameBodyClass = id3v2FrameBodyClass.newInstance().getClass(); |
46 | } catch (IllegalAccessException ex) { |
47 | throw new NullPointerException("IllegalAccessException: No access to run constructor to create copy " + |
48 | ex.getMessage()); |
49 | } catch (InstantiationException ex) { |
50 | throw new NullPointerException("InstantiationException: Unable to instantiate constructor to copy " + |
51 | ex.getMessage()); |
52 | } |
53 | token = copyObject.token; |
54 | } |
55 | |
56 | public void setFrame(final AbstractID3v2Frame frame) { |
57 | if (id3v2FrameBodyClass != null && id3v2FrameBodyClass.equals(frame.getBody().getClass())) { |
58 | //todo add support for more tag matches. only doing text |
59 | // information and URL links right now because i'm lazy |
60 | if (AbstractFrameBodyTextInformation.class.isInstance(frame.getBody())) { |
61 | token = ((AbstractFrameBodyTextInformation) frame.getBody()).getText(); |
62 | } else if (AbstractFrameBodyUrlLink.class.isInstance(frame.getBody())) { |
63 | token = ((AbstractFrameBodyUrlLink) frame.getBody()).getUrlLink(); |
64 | } |
65 | } |
66 | } |
67 | |
68 | /** |
69 | * Sets the ID3v2 frame body that this token represents |
70 | * |
71 | * @param id3v2FrameBodyClass the ID3v2 frame body that this token represents |
72 | */ |
73 | public void setId3v2FrameBodyClass(final Class id3v2FrameBodyClass) { |
74 | this.id3v2FrameBodyClass = id3v2FrameBodyClass; |
75 | } |
76 | |
77 | /** |
78 | * Returns the ID3v2 frame body that this token represents |
79 | * |
80 | * @return the ID3v2 frame body that this token represents |
81 | */ |
82 | public Class getId3v2FrameBodyClass() { |
83 | return id3v2FrameBodyClass; |
84 | } |
85 | |
86 | /** |
87 | * Sets the token that this class contains |
88 | * |
89 | * @param token the token that this class contains |
90 | */ |
91 | public void setToken(final String token) { |
92 | this.token = token.trim(); |
93 | } |
94 | |
95 | /** |
96 | * Return the token that this class contains |
97 | * |
98 | * @return the token that this class contains |
99 | */ |
100 | public String getToken() { |
101 | return token; |
102 | } |
103 | |
104 | /** |
105 | * Reconstruct the filename that is represented by this composite. |
106 | * |
107 | * @return the filename that is represented by this composite. |
108 | */ |
109 | public String composeFilename() { |
110 | return token; |
111 | } |
112 | |
113 | public ID3v2_4 createId3Tag() { |
114 | final ID3v2_4 newTag = new ID3v2_4(); |
115 | if (id3v2FrameBodyClass != null) { |
116 | try { |
117 | final AbstractID3v2FrameBody body = (AbstractID3v2FrameBody) id3v2FrameBodyClass.newInstance(); |
118 | |
119 | //todo need to add support for more frame bodies here |
120 | if (body instanceof AbstractFrameBodyTextInformation) { |
121 | ((AbstractFrameBodyTextInformation) body).setText(token); |
122 | ((AbstractFrameBodyTextInformation) body).setTextEncoding((byte) 0); |
123 | } else if (body instanceof AbstractFrameBodyUrlLink) { |
124 | ((AbstractFrameBodyUrlLink) body).setUrlLink(token); |
125 | } else if (body instanceof FrameBodyCOMM) { |
126 | ((FrameBodyCOMM) body).setText(token); |
127 | ((FrameBodyCOMM) body).setDescription(""); |
128 | ((FrameBodyCOMM) body).setLanguage(TagOptionSingleton.getInstance().getLanguage()); |
129 | ((FrameBodyCOMM) body).setTextEncoding(TagOptionSingleton.getInstance().getTextEncoding()); |
130 | } |
131 | final ID3v2_4Frame frame = new ID3v2_4Frame(); |
132 | frame.setBody(body); |
133 | newTag.setFrame(frame); |
134 | } catch (IllegalAccessException ex) { |
135 | // catch and dont' create the frame |
136 | } catch (InstantiationException ex) { |
137 | // catch and dont' create the frame |
138 | } |
139 | } |
140 | return newTag; |
141 | } |
142 | |
143 | /** |
144 | * Returns an iterator through each <code>FilenameToken</code> in this composite in the correct order for the file |
145 | * name. |
146 | * |
147 | * @return an iterator through each <code>FilenameToken</code> in this composite |
148 | */ |
149 | public Iterator iterator() { |
150 | return new FilenameTokenIterator(this); |
151 | } |
152 | |
153 | /** |
154 | * Match all elements of this composite against the keywords for this class type found in |
155 | * <code>TagOptionSingleton</code>. If the <code>FilenameToken</code> matches the keyword, the token's class is |
156 | * set. |
157 | * |
158 | * @param matchId3v2FrameBodyClass Class of keywords to match against. |
159 | */ |
160 | public void matchAgainstKeyword(final Class matchId3v2FrameBodyClass) { |
161 | if (AbstractID3v2FrameBody.class.isAssignableFrom(matchId3v2FrameBodyClass)) { |
162 | if (TagOptionSingleton.getInstance().isCompositeMatchOverwrite() || id3v2FrameBodyClass == null) { |
163 | final Iterator iterator = TagOptionSingleton.getInstance() |
164 | .getKeywordListIterator(matchId3v2FrameBodyClass); |
165 | final String lowerCaseToken = token.toLowerCase(); |
166 | while (iterator.hasNext()) { |
167 | final String matchString = ((String) iterator.next()).toLowerCase(); |
168 | if (matchString.equals(lowerCaseToken) || |
169 | matchString.indexOf(lowerCaseToken) >= 0 || |
170 | lowerCaseToken.indexOf(matchString) >= 0) { |
171 | setId3v2FrameBodyClass(matchId3v2FrameBodyClass); |
172 | break; |
173 | } |
174 | } |
175 | } |
176 | } |
177 | } |
178 | |
179 | /** |
180 | * Match all elements of this composite against the given tag. If any element of <code>matchTag</code> matches any |
181 | * element of this tag's composite, then this tag's composite leaf node's class is set. |
182 | * |
183 | * @param matchTag Tag to match against |
184 | */ |
185 | public void matchAgainstTag(final AbstractMP3Tag matchTag) { |
186 | if (TagOptionSingleton.getInstance().isCompositeMatchOverwrite() || id3v2FrameBodyClass == null) { |
187 | final ID3v2_4 tag; |
188 | if (matchTag instanceof ID3v2_4) { |
189 | tag = (ID3v2_4) matchTag; |
190 | } else { |
191 | tag = new ID3v2_4(matchTag); |
192 | } |
193 | final Iterator iterator = tag.iterator(); |
194 | AbstractID3v2Frame frame; |
195 | AbstractID3v2FrameBody body; |
196 | String matchString = null; |
197 | final String lowerCaseToken = token.toLowerCase(); |
198 | while (iterator.hasNext()) { |
199 | frame = (ID3v2_4Frame) iterator.next(); |
200 | body = (AbstractID3v2FrameBody) frame.getBody(); |
201 | //todo add support for more tag matches. only doing text |
202 | // information and URL links right now because i'm lazy |
203 | if (body instanceof AbstractFrameBodyTextInformation) { |
204 | matchString = ((AbstractFrameBodyTextInformation) body).getText(); |
205 | if (matchString != null) { |
206 | matchString = matchString.toLowerCase(); |
207 | } |
208 | } else if (body instanceof AbstractFrameBodyUrlLink) { |
209 | matchString = ((AbstractFrameBodyUrlLink) body).getUrlLink(); |
210 | if (matchString != null) { |
211 | matchString = matchString.toLowerCase(); |
212 | } |
213 | } else if (body instanceof FrameBodyCOMM) { |
214 | matchString = ((FrameBodyCOMM) body).getText(); |
215 | } |
216 | if (lowerCaseToken.equals(matchString) || |
217 | matchString != null && |
218 | (matchString.indexOf(lowerCaseToken) >= 0 || lowerCaseToken.indexOf(matchString) >= 0)) { |
219 | setId3v2FrameBodyClass(body.getClass()); |
220 | break; |
221 | } |
222 | } |
223 | } |
224 | } |
225 | |
226 | /** |
227 | * Returns a string containing debug information about this class |
228 | * |
229 | * @return a string containing debug information about this class |
230 | */ |
231 | public String toString() { |
232 | return id3v2FrameBodyClass + ": " + token; |
233 | } |
234 | } |