2002-07-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / AdRotator.cs
1 /**\r
2  * Namespace: System.Web.UI.WebControls\r
3  * Class:     AdRotator\r
4  *\r
5  * Author:  Gaurav Vaish\r
6  * Maintainer: gvaish@iitk.ac.in\r
7  * Implementation: yes\r
8  * Contact: <gvaish@iitk.ac.in>\r
9  * Status:  100%\r
10  *\r
11  * (C) Gaurav Vaish (2001)\r
12  */\r
13 \r
14 using System;\r
15 using System.IO;\r
16 using System.Collections;\r
17 using System.Collections.Specialized;\r
18 using System.Web;\r
19 using System.Web.Caching;\r
20 using System.Web.UI;\r
21 using System.Xml;\r
22 using System.Web.Utils;\r
23 using System.ComponentModel;\r
24 \r
25 namespace System.Web.UI.WebControls\r
26 {\r
27         [DefaultEvent("AdCreated")]\r
28         [DefaultProperty("AdvertisementFile")]\r
29         //TODO: [Designer("??")]\r
30         [ToolboxData("<{0}:AdRotator runat=\"server\" Height=\"60px\" "\r
31                      + "Width=\"468\"></{0}:AdRotator>")]\r
32         [PersistChildren(false)]\r
33         [ParseChildren(true)]\r
34         public class AdRotator: WebControl\r
35         {\r
36 \r
37                 private string advertisementFile;\r
38                 private static readonly object AdCreatedEvent = new object();\r
39 \r
40                 // Will be set values during (On)PreRender-ing\r
41                 private string alternateText;\r
42                 private string imageUrl;\r
43                 private string navigateUrl;\r
44 \r
45                 private string fileDirectory;\r
46 \r
47                 class AdRecord\r
48                 {\r
49                         public IDictionary adProps;\r
50                         public int         hits; // or impressions or clicks\r
51                         public string      keyword;\r
52 \r
53                         public AdRecord(IDictionary adProps)\r
54                         {\r
55                                 this.adProps = adProps;\r
56                                 hits         = 0;\r
57                                 keyword      = String.Empty;\r
58                         }\r
59                 }\r
60 \r
61 /*\r
62  * Loading / Saving data from/to ad file and all the manipulations wrt to the URL...\r
63  * are incorporated by the following functions.\r
64  * GetData(string)\r
65  * LoadAdFile(string)\r
66  * IsAdMatching(AdRecord)\r
67  * ResolveAdUrl(string)\r
68  * SelectAd()\r
69  * The exact control flow will be detailed. Let me first write the functions\r
70  */\r
71 \r
72                 private AdRecord[] LoadAdFile(string file)\r
73                 {\r
74                         Stream      fStream;\r
75                         ArrayList   list;\r
76                         XmlReader   reader;\r
77                         XmlDocument document;\r
78                         XmlNode     topNode, innerNode;\r
79                         IDictionary hybridDict = null;\r
80                         AdRecord[]  adsArray = null;\r
81                         try\r
82                         {\r
83                                 fStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);\r
84                         } catch(Exception e)\r
85                         {\r
86                                 throw new HttpException("AdRotator: Unable to open file");\r
87                         }\r
88                         try\r
89                         {\r
90                                 list = new ArrayList();\r
91                                 reader = new XmlTextReader(fStream);\r
92                                 document = new XmlDocument();\r
93                                 document.Load(reader);\r
94                                 if(document.DocumentElement!=null)\r
95                                 {\r
96                                         if(document.DocumentElement.LocalName=="Advertisements")\r
97                                         {\r
98                                                 topNode = document.DocumentElement.FirstChild;\r
99                                                 while(topNode!=null)\r
100                                                 {\r
101                                                         if(topNode.LocalName=="Ad")\r
102                                                         {\r
103                                                                 innerNode = topNode.FirstChild;\r
104                                                                 while(innerNode!=null)\r
105                                                                 {\r
106                                                                         if(innerNode.NodeType==XmlNodeType.Element)\r
107                                                                         {\r
108                                                                                 if(hybridDict==null)\r
109                                                                                 {\r
110                                                                                         hybridDict = new HybridDictionary();\r
111                                                                                 }\r
112                                                                                 hybridDict.Add(innerNode.LocalName, innerNode.InnerText);\r
113                                                                         }\r
114                                                                         innerNode = innerNode.NextSibling;\r
115                                                                 }\r
116                                                                 if (hybridDict!=null) {\r
117                                                                         list.Add (hybridDict);\r
118                                                                         hybridDict = null;\r
119                                                                 }\r
120                                                         }\r
121                                                         topNode = topNode.NextSibling;\r
122                                                 }\r
123                                         }\r
124                                 }\r
125                                 if(list.Count>0)\r
126                                 {\r
127                                         adsArray = new AdRecord[list.Count];\r
128                                         for(int i=0; i < list.Count; i++)\r
129                                         {\r
130                                                 adsArray[i] = new AdRecord((IDictionary)list[i]);\r
131                                         }\r
132                                 }\r
133                         } catch(Exception e)\r
134                         {\r
135                                 throw new HttpException("AdRotator_Parse_Error" + file);\r
136                         } finally\r
137                         {\r
138                                 fStream.Close();\r
139                         }\r
140                         if(adsArray == null)\r
141                         {\r
142                                 throw new HttpException("AdRotator_No_Advertisements_Found");\r
143                         }\r
144                         return adsArray;\r
145                 }\r
146 \r
147                 [MonoTODO("CacheDependency does nothing")]\r
148                 private AdRecord[] GetData(string file)\r
149                 {\r
150                         string physPath = MapPathSecure(file);\r
151                         string AdKey = "AdRotatorCache: " + physPath;\r
152                         fileDirectory = UrlUtils.GetDirectory(UrlUtils.Combine(TemplateSourceDirectory, file));\r
153                         Cache cache = HttpRuntime.Cache;\r
154                         AdRecord[] records = (AdRecord[])cache[AdKey];\r
155                         if(records==null)\r
156                         {\r
157                                 records = LoadAdFile(physPath);\r
158                                 if(records==null)\r
159                                 {\r
160                                         return null;\r
161                                 }\r
162                                 cache.Insert(AdKey, records, new CacheDependency(physPath));\r
163                         }\r
164                         return records;\r
165                 }\r
166 \r
167                 private IDictionary SelectAd()\r
168                 {\r
169                         AdRecord[] records = GetData(AdvertisementFile);\r
170                         if(records!=null && records.Length!=0)\r
171                         {\r
172                                 int impressions = 0;\r
173                                 for(int i=0 ; i < records.Length; i++)\r
174                                 {\r
175                                         if(IsAdMatching(records[i]))\r
176                                                 impressions += records[i].hits;\r
177                                 }\r
178                                 if(impressions!=0)\r
179                                 {\r
180                                         int rnd = (new Random()).Next(impressions) + 1;\r
181                                         int counter = 0;\r
182                                         int index = 0;\r
183                                         for(int i=0; i < records.Length; i++)\r
184                                         {\r
185                                                 if(IsAdMatching(records[i]))\r
186                                                 {\r
187                                                         if(rnd <= (counter + records[i].hits))\r
188                                                         {\r
189                                                                 index = i;\r
190                                                                 break;\r
191                                                         }\r
192                                                         counter += records[i].hits;\r
193                                                 }\r
194                                         }\r
195                                         return records[index].adProps;\r
196                                 }\r
197                                 //FIXME: the line below added. Where should i init hits to make\r
198                                 //impressions not be 0?\r
199                                 return records [0].adProps;\r
200                         }\r
201                         return null;\r
202                 }\r
203 \r
204                 private bool IsAdMatching(AdRecord currAd)\r
205                 {\r
206                         if (KeywordFilter != String.Empty)\r
207                                 return (0 == String.Compare (currAd.keyword, KeywordFilter, true));\r
208 \r
209                         return true;\r
210                 }\r
211 \r
212                 private string ResolveAdUrl(string relativeUrl)\r
213                 {\r
214                         if(relativeUrl.Length==0 || !UrlUtils.IsRelativeUrl(relativeUrl))\r
215                                 return relativeUrl;\r
216                         string fullUrl = String.Empty;\r
217                         if(fileDirectory != null)\r
218                                 fullUrl = fileDirectory;\r
219                         if(fullUrl.Length == 0)\r
220                                 fullUrl = TemplateSourceDirectory;\r
221                         if(fullUrl.Length == 0)\r
222                                 return relativeUrl;\r
223                         return (fullUrl + relativeUrl);\r
224                 }\r
225 \r
226                 [WebCategory("Action")]\r
227                 [WebSysDescription("AdRotator_OnAdCreated")]\r
228                 public event AdCreatedEventHandler AdCreated\r
229                 {\r
230                         add\r
231                         {\r
232                                 Events.AddHandler(AdCreatedEvent, value);\r
233                         }\r
234                         remove\r
235                         {\r
236                                 Events.RemoveHandler(AdCreatedEvent, value);\r
237                         }\r
238                 }\r
239 \r
240                 public AdRotator(): base()\r
241                 {\r
242                         advertisementFile = string.Empty;\r
243                         fileDirectory     = null;\r
244                 }\r
245 \r
246                 [Bindable(true)]\r
247                 [DefaultValue("")]\r
248                 //[Editor("??")]\r
249                 [WebCategory("Behaviour")]\r
250                 [WebSysDescription("AdRotator_AdvertisementFile")]\r
251                 public string AdvertisementFile\r
252                 {\r
253                         get\r
254                         {\r
255                                 return advertisementFile;\r
256                         }\r
257                         set\r
258                         {\r
259                                 advertisementFile = value;\r
260                         }\r
261                 }\r
262 \r
263                 public override FontInfo Font\r
264                 {\r
265                         get\r
266                         {\r
267                                 return Font;\r
268                         }\r
269                 }\r
270 \r
271                 [Bindable(true)]\r
272                 [DefaultValue("")]\r
273                 [WebCategory("Behaviour")]\r
274                 [WebSysDescription("AdRotator_KeywordFilter")]\r
275                 public string KeywordFilter\r
276                 {\r
277                         get\r
278                         {\r
279                                 object o = ViewState["KeywordFilter"];\r
280                                 if(o!=null)\r
281                                         return (string)o;\r
282                                 return String.Empty;\r
283                         }\r
284                         set\r
285                         {\r
286                                 if(value!=null)\r
287                                         ViewState["KeywordFilter"] = value.Trim();\r
288                         }\r
289                 }\r
290 \r
291                 [Bindable(true)]\r
292                 [DefaultValue("")]\r
293                 [TypeConverter(typeof(TargetConverter))]\r
294                 [WebCategory("Behaviour")]\r
295                 [WebSysDescription("AdRotator_Target")]\r
296                 public string Target\r
297                 {\r
298                         get\r
299                         {\r
300                                 object o = ViewState["Target"];\r
301                                 if(o!=null)\r
302                                         return (string)o;\r
303                                 return String.Empty;\r
304                         }\r
305                         set\r
306                         {\r
307                                 ViewState["Target"] = value;\r
308                         }\r
309                 }\r
310 \r
311                 protected override ControlCollection CreateControlCollection()\r
312                 {\r
313                         return new EmptyControlCollection(this);\r
314                 }\r
315 \r
316                 protected virtual void OnAdCreated(AdCreatedEventArgs e)\r
317                 {\r
318                         if(Events!=null)\r
319                         {\r
320                                 AdCreatedEventHandler aceh = (AdCreatedEventHandler)(Events[AdCreatedEvent]);\r
321                                 if(aceh!=null)\r
322                                         aceh(this, e);\r
323                         }\r
324                 }\r
325 \r
326                 protected override void OnPreRender(EventArgs e)\r
327                 {\r
328                         if(AdvertisementFile!=String.Empty)\r
329                         {\r
330                                 AdCreatedEventArgs acea = new AdCreatedEventArgs(SelectAd());\r
331                                 imageUrl      = acea.ImageUrl;\r
332                                 navigateUrl   = acea.NavigateUrl;\r
333                                 alternateText = acea.AlternateText;\r
334                         }\r
335                 }\r
336 \r
337                 protected override void Render(HtmlTextWriter writer)\r
338                 {\r
339                         HyperLink hLink = new HyperLink();\r
340                         Image adImage = new Image();\r
341                         foreach(IEnumerable current in Attributes.Keys)\r
342                         {\r
343                                 hLink.Attributes[(string)current] = Attributes[(string)current];\r
344                         }\r
345                         if(ID != null && ID.Length > 0)\r
346                                 hLink.ID = ID;\r
347                         hLink.Target    = Target;\r
348                         hLink.AccessKey = AccessKey;\r
349                         hLink.Enabled   = Enabled;\r
350                         hLink.TabIndex  = TabIndex;\r
351                         if (navigateUrl != null && navigateUrl.Length != 0)\r
352                                 hLink.NavigateUrl = ResolveAdUrl (navigateUrl);\r
353                         hLink.RenderBeginTag(writer);\r
354                         if(ControlStyleCreated)\r
355                         {\r
356                                 adImage.ApplyStyle(ControlStyle);\r
357                         }\r
358                         if(imageUrl!=null && imageUrl.Length > 0)\r
359                                 adImage.ImageUrl = ResolveAdUrl(imageUrl);\r
360                         adImage.AlternateText = alternateText;\r
361                         adImage.ToolTip       = ToolTip;\r
362                         adImage.RenderControl(writer);\r
363                         hLink.RenderEndTag(writer);\r
364                 }\r
365         }\r
366 }\r