001    package railo.runtime.tag;
002    
003    
004    import java.awt.Color;
005    import java.io.IOException;
006    import java.util.ArrayList;
007    import java.util.Iterator;
008    import java.util.List;
009    import java.util.Map;
010    
011    import org.apache.commons.collections.map.ReferenceMap;
012    
013    import railo.commons.color.ColorCaster;
014    import railo.commons.io.res.Resource;
015    import railo.commons.io.res.type.file.FileResource;
016    import railo.commons.lang.StringUtil;
017    import railo.runtime.PageContext;
018    import railo.runtime.PageSource;
019    import railo.runtime.exp.ApplicationException;
020    import railo.runtime.exp.ExpressionException;
021    import railo.runtime.exp.PageException;
022    import railo.runtime.ext.tag.BodyTagSupport;
023    import railo.runtime.functions.string.JSStringFormat;
024    import railo.runtime.op.Caster;
025    import railo.runtime.op.Decision;
026    import railo.runtime.type.Collection.Key;
027    import railo.runtime.type.Struct;
028    import railo.runtime.video.VideoInput;
029    import railo.runtime.video.VideoInputImpl;
030    import railo.runtime.video.VideoUtilImpl;
031    
032    /**
033     * implementation of the tag Compiler
034     */
035    public class VideoPlayerJW extends BodyTagSupport {
036    
037            private static final int TYPE_NONE = 0;
038            private static final int TYPE_PLAYLIST = 1;
039            private static final int TYPE_CHAPTERS = 2;
040            
041            private static final int PLAYLIST_NONE = 0;
042            private static final int PLAYLIST_RIGHT = 1;
043            private static final int PLAYLIST_BOTTOM = 2;
044            
045            private static Color BG_COLOR=new Color(51,51,51);
046            private static Color FG_COLOR=new Color(198,198,198);
047            
048            private String video=null;
049            private boolean autostart=false;
050            
051            private railo.runtime.video.Range showPlay=railo.runtime.video.Range.TRUE;
052            private railo.runtime.video.Range showPause=railo.runtime.video.Range.TRUE;
053            private railo.runtime.video.Range showTimeline=railo.runtime.video.Range.TRUE;
054            private List params=new ArrayList();
055            private java.awt.Color bgcolor=BG_COLOR;
056            private java.awt.Color fgcolor=FG_COLOR;
057            private java.awt.Color screencolor=null;
058            private java.awt.Color lightcolor=null;
059            
060            
061            
062            private int width=-1;
063            private int height=-1;
064            private boolean debug;
065            private boolean allowfullscreen;
066            private String strWidth;
067            private String strHeight;
068            private static Map sizes=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT);
069            
070            // JW
071            private Struct passthrough=null;
072            private String preview;
073            
074            private boolean  group=false;
075            private boolean playlistThumbnails=true;
076            private int playlistSize=-1;
077            private int playlist=PLAYLIST_NONE;
078            private String target="_self";
079            private boolean linkfromdisplay;
080            private String overstretch;
081            private boolean download;
082            private String id;
083            private String align;
084            private static int _id=0;
085    
086            public VideoPlayerJW()  {
087                    
088            }
089            
090            /**
091             * @see javax.servlet.jsp.tagext.Tag#release()
092             */ 
093            public void release() {
094                    super.release();
095                    video=null;
096                    autostart=false;
097                    
098                    showPlay=railo.runtime.video.Range.TRUE;
099                    showPause=railo.runtime.video.Range.TRUE;
100                    showTimeline=railo.runtime.video.Range.TRUE;
101                    params.clear();
102                    debug=false;
103                    
104                    id=null;
105                    group=false;
106                    playlist = PLAYLIST_NONE;
107                    playlistSize=-1;
108                    playlistThumbnails=true;
109                    target="_self";
110                    linkfromdisplay=false;
111                    overstretch=null;
112                    /*group="yes"
113                            playlist="right,bottom,none"
114                            playlistSize="300"
115                            playlistThumbnails="300"
116                    
117                    */
118                    align=null;
119                    
120                    
121                    bgcolor=BG_COLOR;
122                    fgcolor=FG_COLOR;
123                    screencolor=null;
124                    lightcolor=null;
125                    width=-1;
126                    height=-1;
127    
128                    strWidth=null;
129                    strHeight=null;
130                    
131                    // JW
132                    passthrough=null;
133                    preview=null;
134                    allowfullscreen=false;
135                    download=false;
136            }
137    
138    
139    
140            protected void setParam(VideoPlayerParamBean param) {
141                    params.add(param);
142            }
143    
144            /**
145             * @param video the video to set
146             */
147            public void setVideo(String video) {
148                    this.video = video;
149            }
150    
151            /**
152             * @param autostart the autostart to set
153             */
154            public void setAutostart(boolean autostart) {
155                    this.autostart = autostart;
156            }
157    
158            /**
159             * @param showPlay the showPlay to set
160             * @throws PageException 
161             */
162            public void setShowplay(String showPlay) throws PageException {
163                    this.showPlay = railo.runtime.video.Range.toRange(showPlay);
164            }
165            public void setId(String id) throws PageException {
166                    this.id=Caster.toVariableName(id);
167            }
168    
169            /**
170             * @param showPause the showPause to set
171             * @throws PageException 
172             */
173            public void setShowpause(String showPause) throws PageException {
174                    this.showPause = railo.runtime.video.Range.toRange(showPause);
175            }
176    
177            /**
178             * @param showTimeline the showTimeline to set
179             * @throws PageException 
180             */
181            public void setShowtimeline(String showTimeline) throws PageException {
182                    this.showTimeline = railo.runtime.video.Range.toRange(showTimeline);
183            }
184    
185            /**
186             * @param color the background color to set
187             * @throws PageException 
188             */
189            public void setBgcolor(String color) throws PageException {
190                    this.bgcolor = ColorCaster.toColor(color);
191            }
192            public void setBackgroundcolor(String color) throws PageException {
193                    setBgcolor(color);
194            }
195            public void setBackground(String color) throws PageException {
196                    setBgcolor(color);
197            }
198            public void setScreencolor(String color) throws PageException {
199                    this.screencolor = ColorCaster.toColor(color);
200            }
201            public void setLightcolor(String color) throws PageException {
202                    this.lightcolor = ColorCaster.toColor(color);
203            }
204            
205    
206            /**
207             * @param color the background color to set
208             * @throws PageException 
209             */
210            public void setFgcolor(String color) throws PageException {
211                    this.fgcolor = ColorCaster.toColor(color);
212            }
213            
214            public void setForeground(String color) throws PageException {
215                    setFgcolor(color);
216            }
217            
218            public void setForegroundcolor(String color) throws PageException {
219                    setFgcolor(color);
220            }
221    
222            /**
223             * @param width the width to set
224             */
225            public void setWidth(String strWidth) {
226                    this.strWidth = strWidth;
227                    this.width = Caster.toIntValue(strWidth,-1);
228            }
229    
230            /**
231             * @param height the height to set
232             */
233            public void setHeight(String strHeight) {
234                    this.strHeight = strHeight;
235                    this.height = Caster.toIntValue(strHeight,-1);
236            }
237    
238            /**
239             * @throws IOException 
240             * @see javax.servlet.jsp.tagext.Tag#doStartTag()
241             */
242            public int doStartTag() throws PageException {
243                    return EVAL_BODY_INCLUDE;
244            }
245            public int doEndTag() throws PageException {
246    
247                    // fill top video to params
248                    if(video!=null) {
249                            VideoPlayerParamBean vppb = new VideoPlayerParamBean();
250                            vppb.setVideo(pageContext,video);
251                            if(!StringUtil.isEmpty(preview))vppb.setImage(pageContext,preview);
252                            params.add(vppb);
253                    }
254                    else {
255                            if(!StringUtil.isEmpty(preview))
256                                    throw new ApplicationException("attribute [preview] is only allowed when attribute [video] is used");
257                    }
258                    
259                    if(params.size()==0)
260                            throw new ApplicationException("you have to define at least one video source");
261                    
262                    
263                    
264                    
265                    
266                    // calculate dimension
267                    int[] dim = calculateDimension(pageContext,params,width,strWidth,height,strHeight);
268    
269                    //print.out(width+":"+height);
270                    //print.out(strWidth+":"+strHeight);
271                    width=dim[0];
272                    height=dim[1];
273                    
274                    //print.out(width+":"+height);
275                    
276                    
277                    // playlist
278                    int dspHeight=-1,dspWidth=-1;
279                    if(playlist!=PLAYLIST_NONE) {
280                            if(playlistSize<20)playlistSize=playlist==PLAYLIST_BOTTOM?100:200; 
281                            if(playlist==PLAYLIST_BOTTOM) {
282                                    dspHeight=height;
283                                    height+=playlistSize;
284                            }
285                            else {
286                                    dspWidth=width;
287                                    width+=playlistSize;
288                            }
289                    }
290                    else playlistThumbnails=false;
291                    
292                    
293                    VideoPlayerParamBean param;
294                            
295                    
296                    String id=getId();//
297                    String placeholderId="ph_"+id;
298                    String flashId="swf_"+id;
299                    
300                    StringBuffer sb=new StringBuffer();
301                    
302                    write(sb,"<script type=\"text/javascript\" src=\"/railo-context/swfobject.js.cfm\"></script>");
303                    write(sb,"<div ");                   
304                    
305                    
306                    if(passthrough!=null) {
307                            Key[] keys = passthrough.keys();
308                            String key;
309                            for(int i=0;i<keys.length;i++) {
310                                    key=keys[i].getString();
311                                    if(StringUtil.startsWithIgnoreCase(key, "div."))
312                                            write(sb,key.substring(4)+"=\""+Caster.toString(passthrough.get(keys[i]))+"\" ");
313                            }
314                    }
315                    write(sb,(align!=null?"align=\""+align+"\"":"")+" id=\""+placeholderId+"\"><a href=\"http://www.macromedia.com/go/getflashplayer\">Get the Flash Player</a> to see this player.</a></div>");                 
316                    
317                    
318                    
319                    write(sb,"<script type=\"text/javascript\">\n");                  
320                    write(sb,"var so = new SWFObject(\"/railo-context/mediaplayer.swf.cfm\", \""+flashId+"\", \""+width+"\", \""+(height)+"\", \"8\", \""+format("#",bgcolor)+"\");\n");                    
321                    
322                    // script
323                    addParam(sb,"allowscriptaccess","always");
324                    addVariable(sb,"enablejs","true");
325                    addVariable(sb,"javascriptid",flashId);
326                    
327                    addVariable(sb,"shuffle","false");
328                    addVariable(sb,"linktarget",target);
329                    addVariable(sb,"linkfromdisplay",Caster.toString(linkfromdisplay));
330                    addVariable(sb,"abouttxt","Railo Video Player");
331                    addVariable(sb,"aboutlnk","http://www.getrailo.org");
332                    
333                    // control
334                    addParam(sb,"allowfullscreen",Caster.toString(allowfullscreen));
335                    addParam(sb,"usefullscreen",Caster.toString(allowfullscreen));
336                    addVariable(sb,"autostart",Caster.toString(autostart));
337                    if(!StringUtil.isEmpty(overstretch))addVariable(sb,"overstretch",overstretch);
338                    addVariable(sb,"showdownload",Caster.toString(download));
339                    
340                    
341                    
342                    
343                    // color
344                    if(lightcolor==null)lightcolor=fgcolor.brighter();
345                    if(screencolor==null)screencolor=Color.BLACK;//fgcolor.brighter();
346                    addVariable(sb,"backcolor",format("0x",bgcolor));
347                    addVariable(sb,"frontcolor",format("0x",fgcolor));
348                    addVariable(sb,"lightcolor",format("0x",lightcolor));
349                    addVariable(sb,"screencolor",format("0x",screencolor));
350                    
351                    if(passthrough!=null) {
352                            Key[] keys = passthrough.keys();
353                            String key;
354                            for(int i=0;i<keys.length;i++) {
355                                    key=keys[i].getString();
356                                    if(StringUtil.startsWithIgnoreCase(key, "param."))
357                                            addParam(sb,key.substring(6),Caster.toString(passthrough.get(keys[i])));
358                                    else if(StringUtil.startsWithIgnoreCase(key, "variable."))
359                                            addVariable(sb,key.substring(9),Caster.toString(passthrough.get(keys[i])));
360                                    else if(StringUtil.startsWithIgnoreCase(key, "div."));
361                                    else
362                                            addVariable(sb,key,Caster.toString(passthrough.get(keys[i])));
363                            }
364                    }
365    
366                    if(params.size()>1 && group) addVariable(sb,"repeat","true");
367                    
368                    /*if(playlist!=PLAYLIST_NONE) {
369                            if(playlistSize<20)playlistSize=playlist==PLAYLIST_BOTTOM?300:200; 
370                            if(playlist==PLAYLIST_BOTTOM) {
371                                    addVariable(sb,"displayheight",Caster.toString(height));
372                                    height+=playlistSize;
373                            }
374                            else {
375                                    addVariable(sb,"displaywidth",Caster.toString(width));
376                                    width+=playlistSize;
377                            }
378                            if(playlistThumbnails && hasImages())addVariable(sb,"thumbsinplaylist","true");
379                    }*/
380    
381                    // dimension
382                    if(dspWidth>0)addVariable(sb,"displaywidth",Caster.toString(dspWidth));
383                    if(dspHeight>0)addVariable(sb,"displayheight",Caster.toString(dspHeight));
384                    addVariable(sb,"width",Caster.toString(width));
385                    addVariable(sb,"height",Caster.toString(height));
386                    if(playlistThumbnails && hasImages())addVariable(sb,"thumbsinplaylist","true");
387                    
388                    //if(preview!=null) addVariable(sb,"image",toPath(preview));
389                    //Iterator it = params.iterator();
390                    //addVariable("file","/rvp/videos/David.flv");
391                    //addVariable("captions","http://localhost:8080/caption.cfm");
392                    //while(it.hasNext()) {
393                            //param=(VideoPlayerParamBean) it.next();
394                            //addVariable(sb,"file",toPath(param.getResource()));
395                            //break;        
396                    //}
397                    //addVariable("image","video.jpg");
398                    
399                    write(sb,"so.write(\""+placeholderId+"\");\n");
400                    //if(params.size()>1) {
401                    Iterator it = params.iterator();
402                    while(it.hasNext()) {
403                            param=(VideoPlayerParamBean) it.next();
404                            addItem(sb,flashId,param);
405                    }
406                    //}
407                    write(sb,"</script>");
408                    try {
409                            if(debug) {
410                                    pageContext.forceWrite("<pre>"+StringUtil.replace(sb.toString(), "<", "&lt;", false)+"</pre>");
411                            }
412                            pageContext.forceWrite(sb.toString());
413                            
414                            
415                    } 
416                    catch (IOException e) {
417                            
418                    }
419                return EVAL_PAGE;
420            }
421    
422            private synchronized String getId() {
423                    if(!StringUtil.isEmpty(id)) return id;
424                    _id++;
425                    if(_id<0) _id=1;
426                    return ""+_id; 
427            }
428    
429            private boolean hasImages() {
430                    Iterator it = params.iterator();
431                    while(it.hasNext()) {
432                            if(((VideoPlayerParamBean) it.next()).getImage()!=null) return true;
433                    }
434                    return false;
435            }
436    
437            private void addItem(StringBuffer sb, String id, VideoPlayerParamBean param) {
438                    //sb.append("setTimeout('thisMovie(\""+id+"\").addItem({file:\""+JSStringFormat.invoke(path)+"\"},null);',1000);\n");
439                    
440                    // file
441                    String file = "file:'"+JSStringFormat.invoke(toPath(param.getResource()))+"'";
442                    
443                    // image
444                    String image="";
445                    if(param.getImage()!=null) {
446                            image=",image:'"+JSStringFormat.invoke(toPath(param.getImage()))+"'";
447                    }
448                    
449                    // title
450                    String title="";
451                    if(!StringUtil.isEmpty(param.getTitle())) {
452                            title=",title:'"+JSStringFormat.invoke(param.getTitle())+"'";
453                    }
454                    
455                    // link
456                    String link="";
457                    if(!StringUtil.isEmpty(param.getLink())) {
458                            link=",link:'"+JSStringFormat.invoke(param.getLink())+"'";
459                    }
460                    
461                    // author
462                    String author="";
463                    if(!StringUtil.isEmpty(param.getAuthor())) {
464                            author=",author:'"+JSStringFormat.invoke(param.getAuthor())+"'";
465                    }
466                    
467                    sb.append("addItem('"+id+"',{"+file+title+image+link+author+"});\n");
468            }
469    
470            private void addVariable(StringBuffer sb, String name, String value) {
471                    value=JSStringFormat.invoke(value);
472                    if(!(value.equals("false") || value.equals("true")))
473                            value="'"+value+"'";
474                    sb.append("so.addVariable('"+JSStringFormat.invoke(name)+"',"+value+");\n");
475            }
476    
477            private void addParam(StringBuffer sb,String name, String value) {
478                    sb.append("so.addParam('"+name+"','"+value+"');\n");
479            }
480    
481            private static int[] calculateDimension(PageContext pc,List params,int width, String strWidth,int height, String strHeight) throws PageException {
482                    Iterator it = params.iterator();
483                    ArrayList sources=new ArrayList();
484                    //Resource[] sources=new Resource[params.size()];
485                    VideoPlayerParamBean param;
486                    
487                    while(it.hasNext()) {
488                            param = (VideoPlayerParamBean) it.next();
489                            if(param.getVideo()!=null)
490                                    sources.add(new VideoInputImpl(param.getVideo()));
491                    }
492                    return VideoUtilImpl.getInstance().calculateDimension(pc, (VideoInput[])sources.toArray(new VideoInput[sources.size()]), width, strWidth, height, strHeight);
493                    
494            }
495    
496            private String toPath(Resource res) {
497                            if(!(res instanceof FileResource)) return res.getAbsolutePath();
498                            
499                            //Config config=pageContext.getConfig();
500                            PageSource ps = pageContext.toPageSource(res,null);
501                            if(ps==null) return res.getAbsolutePath();
502                            
503                            String realPath = ps.getRealpath();
504                            realPath=realPath.replace('\\', '/');
505                            if(realPath.endsWith("/"))realPath=realPath.substring(0,realPath.length()-1);
506                            
507                            //print.out("real:"+realPath);
508                            String mapping=ps.getMapping().getVirtual();
509                            mapping=mapping.replace('\\', '/');
510                            if(mapping.endsWith("/"))mapping=mapping.substring(0,mapping.length()-1);
511                            
512                            return mapping+realPath;
513                    
514                    
515            }
516    
517    
518    
519            private void write(StringBuffer sb, String string) {
520                    sb.append(string);
521            }
522    
523    
524    
525            private static String format(String prefix, Color color) {
526                    return prefix+toHex(color.getRed())+toHex(color.getGreen())+toHex(color.getBlue());
527            }
528    
529    
530    
531            private static String toHex(int value) {
532                    String str = Integer.toHexString(value);
533                    if(str.length()==1) return "0".concat(str);
534                    return str;
535            }
536    
537            /**
538             * @param debug the debug to set
539             */
540            public void setDebug(boolean debug) {
541                    this.debug = debug;
542            }
543    
544            /**
545             * @param passthrough the passthrough to set
546             */
547            public void setPassthrough(Struct passthrough) {
548                    this.passthrough = passthrough;
549            }
550    
551            /**
552             * @param preview the preview to set
553             * @throws ExpressionException 
554             */
555            public void setPreview(String preview) {
556                    this.preview = preview;//ResourceUtil.toResourceExisting(pageContext, preview);
557            }
558    
559            /**
560             * @param allowfullscreen the allowfullscreen to set
561             */
562            public void setAllowfullscreen(boolean allowfullscreen) {
563                    this.allowfullscreen = allowfullscreen;
564            }
565            
566            public void setAlign(String strAlign) throws ApplicationException {
567                    if(StringUtil.isEmpty(strAlign)) return;
568                    strAlign=strAlign.trim().toLowerCase();
569                    if("right".equals(strAlign)) this.align = "right";
570                    else if("center".equals(strAlign)) this.align = "center";
571                    else if("left".equals(strAlign)) this.align = "left";
572                    else 
573                            throw new ApplicationException("invalid value for attribute align ["+strAlign+"], valid values are [left,center,right]");
574            }
575    
576            /**
577             * @param group the group to set
578             */
579            public void setGroup(boolean group) {
580                    this.group = group;
581            }
582            public void setLinktarget(String target)  {
583                    this.target = target;
584            }
585            public void setTarget(String target)  {
586                    this.target = target;
587            }
588            public void setLinkfromdisplay(boolean linkfromdisplay)  {
589                    this.linkfromdisplay = linkfromdisplay;
590            }
591    
592            /**
593             * @param playlistThumbnails the playlistThumbnails to set
594             */
595            public void setPlaylistthumbnails(boolean playlistThumbnails) {
596                    this.playlistThumbnails = playlistThumbnails;
597            }
598            public void setThumbnails(boolean playlistThumbnails) {
599                    setPlaylistthumbnails(playlistThumbnails);
600            }
601            public void setThumbs(boolean playlistThumbnails) {
602                    setPlaylistthumbnails(playlistThumbnails);
603            }
604    
605            /**
606             * @param playlistSize the playlistSize to set
607             */
608            public void setPlaylistsize(double playlistSize) throws ApplicationException {
609                    if(playlistSize<=40) throw new ApplicationException("playlist size has to be a positive number, at least 41px");
610                    this.playlistSize = (int) playlistSize;
611            }
612    
613            /**
614             * @param playlist the playlist to set
615             */
616            public void setPlaylist(String strPlaylist) throws PageException {
617                    strPlaylist=strPlaylist.trim().toLowerCase();
618                    if("right".equals(strPlaylist))                 playlist=PLAYLIST_RIGHT;
619                    else if("bottom".equals(strPlaylist))   playlist=PLAYLIST_BOTTOM;
620                    else if("none".equals(strPlaylist))     playlist=PLAYLIST_NONE;
621                    else if(Decision.isBoolean(strPlaylist)) {
622                            playlist=Caster.toBooleanValue(strPlaylist)?PLAYLIST_BOTTOM:PLAYLIST_NONE;
623                    }
624                    else throw new ApplicationException("invalid playlist definition ["+strPlaylist+"], valid values are [right,bottom,none]");
625            }
626    
627            /**
628             * @param overstretch the overstretch to set
629             */
630            public void setOverstretch(String overstretch) throws PageException {
631                    overstretch=overstretch.trim().toLowerCase();
632                    if("fit".equals(overstretch))           overstretch="fit";
633                    else if("none".equals(overstretch)) overstretch="none";
634                    else if("proportion".equals(overstretch)) overstretch="true";
635                    else if(Decision.isBoolean(overstretch)) {
636                            overstretch=Caster.toString(Caster.toBooleanValue(overstretch));
637                    }
638                    else throw new ApplicationException("invalid overstretch definition ["+overstretch+"], valid values are [fit,none,true,false]");
639                    
640                    this.overstretch = overstretch;
641            }
642    
643            /**
644             * @param download the download to set
645             */
646            public void setDownload(boolean download) {
647                    this.download = download;
648            }
649            
650    }