001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.tag;
020
021import javax.servlet.jsp.tagext.Tag;
022
023import lucee.runtime.exp.ApplicationException;
024import lucee.runtime.exp.PageException;
025import lucee.runtime.ext.tag.TagImpl;
026import lucee.runtime.functions.other.GetBaseTagData;
027import lucee.runtime.op.Caster;
028import lucee.runtime.op.Decision;
029import lucee.runtime.type.Array;
030import lucee.runtime.type.ArrayImpl;
031import lucee.runtime.type.Collection;
032import lucee.runtime.type.Collection.Key;
033import lucee.runtime.type.KeyImpl;
034import lucee.runtime.type.Struct;
035
036/**
037* Allows subtag data to be saved with the base tag. Applies only to custom tags.
038*
039*
040*
041**/
042public final class Associate extends TagImpl {
043
044        private static final Key ASSOC_ATTRS = KeyImpl.intern("AssocAttribs");
045        
046
047        /** The name of the structure in which the base tag stores subtag data. */
048        private Collection.Key datacollection=ASSOC_ATTRS;
049
050        /** The name of the base tag. */
051        private String basetag;
052
053        @Override
054        public void release()   {
055                super.release();
056                datacollection=ASSOC_ATTRS;
057        }
058
059        /** set the value datacollection
060        *  The name of the structure in which the base tag stores subtag data.
061        * @param datacollection value to set
062        **/
063        public void setDatacollection(String datacollection)    {
064                this.datacollection=KeyImpl.init(datacollection);
065        }
066
067        /** set the value basetag
068        *  The name of the base tag.
069        * @param basetag value to set
070        **/
071        public void setBasetag(String basetag)  {
072                this.basetag=basetag;
073        }
074
075
076        @Override
077        public int doStartTag() throws PageException    {
078                
079                // current
080        CFTag current=getCFTag();
081        Struct value;
082        if(current==null || (value=current.getAttributesScope())==null) 
083                throw new ApplicationException("invalid context, tag is no inside a custom tag");
084        
085        // parent
086        CFTag parent=GetBaseTagData.getParentCFTag(current.getParent(), basetag, -1);
087        if(parent==null) throw new ApplicationException("there is no parent tag with name ["+basetag+"]");
088        
089        Struct thisTag=parent.getThis();
090        Object obj=thisTag.get(datacollection,null);
091        
092        Array array;
093
094        if(obj==null) {
095            array=new ArrayImpl(new Object[]{value});
096            thisTag.set(datacollection,array);   
097        }
098        else if(Decision.isArray(obj) && (array=Caster.toArray(obj)).getDimension()==1) {
099            array.append(value);
100        }
101        else {
102            array=new ArrayImpl(new Object[]{obj,value});
103            thisTag.set(datacollection,array);   
104        }
105                return SKIP_BODY; 
106        }
107
108        /*private static CFTag getParentCFTag(Tag srcTag,String trgTagName) {
109        String pureName=trgTagName;
110        CFTag cfTag;
111        if(StringUtil.startsWithIgnoreCase(pureName,"cf_")) {
112            pureName=pureName.substring(3);
113        }
114        if(StringUtil.startsWithIgnoreCase(pureName,"cf")) {
115            pureName=pureName.substring(2);
116        }
117        int count=0;
118        while((srcTag=srcTag.getParent())!=null) {
119                if(srcTag instanceof CFTag) {
120                if(count++==0)continue;
121                cfTag=(CFTag)srcTag;
122                if(cfTag instanceof CFTagCore){
123                        CFTagCore tc=(CFTagCore) cfTag;
124                        if(tc.getName().equalsIgnoreCase(pureName))
125                                return cfTag;
126                        continue;
127                }
128                if(cfTag.getAppendix().equalsIgnoreCase(pureName)) {
129                    return cfTag;
130                }
131            }
132        }
133        return null;
134    }*/
135        
136        private CFTag getCFTag() {
137        Tag tag=this;
138        while((tag=tag.getParent())!=null) {
139            if(tag instanceof CFTag) {
140                return (CFTag)tag;
141            }
142        }
143        return null;
144    }
145
146    @Override
147        public int doEndTag()   {
148                return EVAL_PAGE;
149        }
150
151}