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    import java.util.Map.Entry;
011    
012    import org.apache.commons.collections.map.ReferenceMap;
013    
014    import railo.commons.color.ColorCaster;
015    import railo.commons.io.res.Resource;
016    import railo.commons.io.res.type.file.FileResource;
017    import railo.commons.lang.StringUtil;
018    import railo.runtime.PageContext;
019    import railo.runtime.PageSource;
020    import railo.runtime.exp.ApplicationException;
021    import railo.runtime.exp.ExpressionException;
022    import railo.runtime.exp.PageException;
023    import railo.runtime.ext.tag.BodyTagSupport;
024    import railo.runtime.functions.string.JSStringFormat;
025    import railo.runtime.op.Caster;
026    import railo.runtime.op.Decision;
027    import railo.runtime.type.Collection.Key;
028    import railo.runtime.type.Struct;
029    import railo.runtime.video.VideoInput;
030    import railo.runtime.video.VideoInputImpl;
031    import railo.runtime.video.VideoUtilImpl;
032    
033    /**
034     * implementation of the tag Compiler
035     */
036    public class VideoPlayerJW extends BodyTagSupport {
037    
038            private static final int TYPE_NONE = 0;
039            private static final int TYPE_PLAYLIST = 1;
040            private static final int TYPE_CHAPTERS = 2;
041            
042            private static final int PLAYLIST_NONE = 0;
043            private static final int PLAYLIST_RIGHT = 1;
044            private static final int PLAYLIST_BOTTOM = 2;
045            
046            private static Color BG_COLOR=new Color(51,51,51);
047            private static Color FG_COLOR=new Color(198,198,198);
048            
049            private String video=null;
050            private boolean autostart=false;
051            
052            private railo.runtime.video.Range showPlay=railo.runtime.video.Range.TRUE;
053            private railo.runtime.video.Range showPause=railo.runtime.video.Range.TRUE;
054            private railo.runtime.video.Range showTimeline=railo.runtime.video.Range.TRUE;
055            private List params=new ArrayList();
056            private java.awt.Color bgcolor=BG_COLOR;
057            private java.awt.Color fgcolor=FG_COLOR;
058            private java.awt.Color screencolor=null;
059            private java.awt.Color lightcolor=null;
060            
061            
062            
063            private int width=-1;
064            private int height=-1;
065            private boolean debug;
066            private boolean allowfullscreen;
067            private String strWidth;
068            private String strHeight;
069            private static Map sizes=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT);
070            
071            // JW
072            private Struct passthrough=null;
073            private String preview;
074            
075            private boolean  group=false;
076            private boolean playlistThumbnails=true;
077            private int playlistSize=-1;
078            private int playlist=PLAYLIST_NONE;
079            private String target="_self";
080            private boolean linkfromdisplay;
081            private String overstretch;
082            private boolean download;
083            private String id;
084            private String align;
085            private static int _id=0;
086    
087            public VideoPlayerJW()  {
088                    
089            }
090            
091            @Override 
092            public void release() {
093                    super.release();
094                    video=null;
095                    autostart=false;
096                    
097                    showPlay=railo.runtime.video.Range.TRUE;
098                    showPause=railo.runtime.video.Range.TRUE;
099                    showTimeline=railo.runtime.video.Range.TRUE;
100                    params.clear();
101                    debug=false;
102                    
103                    id=null;
104                    group=false;
105                    playlist = PLAYLIST_NONE;
106                    playlistSize=-1;
107                    playlistThumbnails=true;
108                    target="_self";
109                    linkfromdisplay=false;
110                    overstretch=null;
111                    /*group="yes"
112                            playlist="right,bottom,none"
113                            playlistSize="300"
114                            playlistThumbnails="300"
115                    
116                    */
117                    align=null;
118                    
119                    
120                    bgcolor=BG_COLOR;
121                    fgcolor=FG_COLOR;
122                    screencolor=null;
123                    lightcolor=null;
124                    width=-1;
125                    height=-1;
126    
127                    strWidth=null;
128                    strHeight=null;
129                    
130                    // JW
131                    passthrough=null;
132                    preview=null;
133                    allowfullscreen=false;
134                    download=false;
135            }
136    
137    
138    
139            protected void setParam(VideoPlayerParamBean param) {
140                    params.add(param);
141            }
142    
143            /**
144             * @param video the video to set
145             */
146            public void setVideo(String video) {
147                    this.video = video;
148            }
149    
150            /**
151             * @param autostart the autostart to set
152             */
153            public void setAutostart(boolean autostart) {
154                    this.autostart = autostart;
155            }
156    
157            /**
158             * @param showPlay the showPlay to set
159             * @throws PageException 
160             */
161            public void setShowplay(String showPlay) throws PageException {
162                    this.showPlay = railo.runtime.video.Range.toRange(showPlay);
163            }
164            public void setId(String id) throws PageException {
165                    this.id=Caster.toVariableName(id);
166            }
167    
168            /**
169             * @param showPause the showPause to set
170             * @throws PageException 
171             */
172            public void setShowpause(String showPause) throws PageException {
173                    this.showPause = railo.runtime.video.Range.toRange(showPause);
174            }
175    
176            /**
177             * @param showTimeline the showTimeline to set
178             * @throws PageException 
179             */
180            public void setShowtimeline(String showTimeline) throws PageException {
181                    this.showTimeline = railo.runtime.video.Range.toRange(showTimeline);
182            }
183    
184            /**
185             * @param color the background color to set
186             * @throws PageException 
187             */
188            public void setBgcolor(String color) throws PageException {
189                    this.bgcolor = ColorCaster.toColor(color);
190            }
191            public void setBackgroundcolor(String color) throws PageException {
192                    setBgcolor(color);
193            }
194            public void setBackground(String color) throws PageException {
195                    setBgcolor(color);
196            }
197            public void setScreencolor(String color) throws PageException {
198                    this.screencolor = ColorCaster.toColor(color);
199            }
200            public void setLightcolor(String color) throws PageException {
201                    this.lightcolor = ColorCaster.toColor(color);
202            }
203            
204    
205            /**
206             * @param color the background color to set
207             * @throws PageException 
208             */
209            public void setFgcolor(String color) throws PageException {
210                    this.fgcolor = ColorCaster.toColor(color);
211            }
212            
213            public void setForeground(String color) throws PageException {
214                    setFgcolor(color);
215            }
216            
217            public void setForegroundcolor(String color) throws PageException {
218                    setFgcolor(color);
219            }
220    
221            /**
222             * @param width the width to set
223             */
224            public void setWidth(String strWidth) {
225                    this.strWidth = strWidth;
226                    this.width = Caster.toIntValue(strWidth,-1);
227            }
228    
229            /**
230             * @param height the height to set
231             */
232            public void setHeight(String strHeight) {
233                    this.strHeight = strHeight;
234                    this.height = Caster.toIntValue(strHeight,-1);
235            }
236    
237            @Override
238            public int doStartTag() throws PageException {
239                    return EVAL_BODY_INCLUDE;
240            }
241            public int doEndTag() throws PageException {
242    
243                    // fill top video to params
244                    if(video!=null) {
245                            VideoPlayerParamBean vppb = new VideoPlayerParamBean();
246                            vppb.setVideo(pageContext,video);
247                            if(!StringUtil.isEmpty(preview))vppb.setImage(pageContext,preview);
248                            params.add(vppb);
249                    }
250                    else {
251                            if(!StringUtil.isEmpty(preview))
252                                    throw new ApplicationException("attribute [preview] is only allowed when attribute [video] is used");
253                    }
254                    
255                    if(params.size()==0)
256                            throw new ApplicationException("you have to define at least one video source");
257                    
258                    
259                    
260                    
261                    
262                    // calculate dimension
263                    int[] dim = calculateDimension(pageContext,params,width,strWidth,height,strHeight);
264    
265                    //print.out(width+":"+height);
266                    //print.out(strWidth+":"+strHeight);
267                    width=dim[0];
268                    height=dim[1];
269                    
270                    //print.out(width+":"+height);
271                    
272                    
273                    // playlist
274                    int dspHeight=-1,dspWidth=-1;
275                    if(playlist!=PLAYLIST_NONE) {
276                            if(playlistSize<20)playlistSize=playlist==PLAYLIST_BOTTOM?100:200; 
277                            if(playlist==PLAYLIST_BOTTOM) {
278                                    dspHeight=height;
279                                    height+=playlistSize;
280                            }
281                            else {
282                                    dspWidth=width;
283                                    width+=playlistSize;
284                            }
285                    }
286                    else playlistThumbnails=false;
287                    
288                    
289                    VideoPlayerParamBean param;
290                            
291                    
292                    String id=getId();//
293                    String placeholderId="ph_"+id;
294                    String flashId="swf_"+id;
295                    
296                    StringBuffer sb=new StringBuffer();
297                    
298                    write(sb,"<script type=\"text/javascript\" src=\"/railo-context/swfobject.js.cfm\"></script>");
299                    write(sb,"<div ");                   
300                    
301                    
302                    if(passthrough!=null) {
303                            Iterator<Entry<Key, Object>> it = passthrough.entryIterator();
304                            Entry<Key, Object> e;
305                            String key;
306                            while(it.hasNext()) {
307                                    e = it.next();
308                                    key=e.getKey().getString();
309                                    if(StringUtil.startsWithIgnoreCase(key, "div."))
310                                            write(sb,key.substring(4)+"=\""+Caster.toString(e.getValue())+"\" ");
311                            }
312                    }
313                    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>");                 
314                    
315                    
316                    
317                    write(sb,"<script type=\"text/javascript\">\n");                  
318                    write(sb,"var so = new SWFObject(\"/railo-context/mediaplayer.swf.cfm\", \""+flashId+"\", \""+width+"\", \""+(height)+"\", \"8\", \""+format("#",bgcolor)+"\");\n");                    
319                    
320                    // script
321                    addParam(sb,"allowscriptaccess","always");
322                    addVariable(sb,"enablejs","true");
323                    addVariable(sb,"javascriptid",flashId);
324                    
325                    addVariable(sb,"shuffle","false");
326                    addVariable(sb,"linktarget",target);
327                    addVariable(sb,"linkfromdisplay",Caster.toString(linkfromdisplay));
328                    addVariable(sb,"abouttxt","Railo Video Player");
329                    addVariable(sb,"aboutlnk","http://www.getrailo.org");
330                    
331                    // control
332                    addParam(sb,"allowfullscreen",Caster.toString(allowfullscreen));
333                    addParam(sb,"usefullscreen",Caster.toString(allowfullscreen));
334                    addVariable(sb,"autostart",Caster.toString(autostart));
335                    if(!StringUtil.isEmpty(overstretch))addVariable(sb,"overstretch",overstretch);
336                    addVariable(sb,"showdownload",Caster.toString(download));
337                    
338                    
339                    
340                    
341                    // color
342                    if(lightcolor==null)lightcolor=fgcolor.brighter();
343                    if(screencolor==null)screencolor=Color.BLACK;//fgcolor.brighter();
344                    addVariable(sb,"backcolor",format("0x",bgcolor));
345                    addVariable(sb,"frontcolor",format("0x",fgcolor));
346                    addVariable(sb,"lightcolor",format("0x",lightcolor));
347                    addVariable(sb,"screencolor",format("0x",screencolor));
348                    
349                    if(passthrough!=null) {
350                            Iterator<Entry<Key, Object>> it = passthrough.entryIterator();
351                            Entry<Key, Object> e;
352                            String key;
353                            while(it.hasNext()) {
354                                    e = it.next();
355                                    key=e.getKey().getString();
356                                    if(StringUtil.startsWithIgnoreCase(key, "param."))
357                                            addParam(sb,key.substring(6),Caster.toString(e.getValue()));
358                                    else if(StringUtil.startsWithIgnoreCase(key, "variable."))
359                                            addVariable(sb,key.substring(9),Caster.toString(e.getValue()));
360                                    else if(StringUtil.startsWithIgnoreCase(key, "div."));
361                                    else
362                                            addVariable(sb,key,Caster.toString(e.getValue()));
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    }