Add licensing info
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / AdRotator.cs
1 //
2 // System.Web.UI.WebControls.AdRotator.cs
3 //
4 // Authors:
5 //   Gaurav Vaish (gvaish@iitk.ac.in)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //
9 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
10 // (C) Gaurav Vaish (2002)
11 // (C) 2003 Andreas Nahr
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.IO;
37 using System.Collections;
38 using System.Collections.Specialized;
39 using System.Web;
40 using System.Web.Caching;
41 using System.Web.UI;
42 using System.Xml;
43 using System.Web.Util;
44 using System.ComponentModel;
45 using System.ComponentModel.Design;
46
47 namespace System.Web.UI.WebControls
48 {
49         [DefaultEvent("AdCreated")]
50         [DefaultProperty("AdvertisementFile")]
51         [Designer ("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
52         [ToolboxData("<{0}:AdRotator runat=\"server\" Height=\"60px\" "
53         + "Width=\"468\"></{0}:AdRotator>")]
54         public class AdRotator: WebControl
55         {
56                 string advertisementFile;
57                 static readonly object AdCreatedEvent = new object();
58
59                 // Will be set values during (On)PreRender-ing
60                 string alternateText;
61                 string imageUrl;
62                 string navigateUrl;
63                 string fileDirectory;
64                 Random random;
65
66                 public AdRotator ()
67                 {
68                         advertisementFile = "";
69                         fileDirectory     = null;
70                 }
71
72                 AdRecord[] LoadAdFile (string file)
73                 {
74                         Stream fStream;
75                         try {
76                                 fStream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read);
77                         } catch (Exception e) {
78                                 throw new HttpException("AdRotator: Unable to open file", e);
79                         }
80
81                         ArrayList list = new ArrayList ();
82                         try {
83                                 IDictionary hybridDict = null;
84                                 XmlDocument document = new XmlDocument ();
85                                 document.Load (fStream);
86
87                                 XmlElement docElem = document.DocumentElement;
88
89                                 if (docElem == null)
90                                         throw new HttpException ("No advertisements found");
91
92                                 if (docElem.LocalName != "Advertisements")
93                                         throw new HttpException ("No advertisements found: invalid document element");
94
95                                 XmlNode node = docElem.FirstChild;
96                                 while (node != null) {
97                                         if (node.LocalName == "Ad") {
98                                                 XmlNode innerNode = node.FirstChild;
99                                                 while (innerNode != null) {
100                                                         if (node.NodeType == XmlNodeType.Element) {
101                                                                 if (hybridDict == null)
102                                                                         hybridDict = new HybridDictionary ();
103
104                                                                 hybridDict.Add (innerNode.LocalName, innerNode.InnerText);
105                                                         }
106                                                         innerNode = innerNode.NextSibling;
107                                                 }
108
109                                                 if (hybridDict != null) {
110                                                         list.Add (hybridDict);
111                                                         hybridDict = null;
112                                                 }
113                                         }
114                                         node = node.NextSibling;
115                                 }
116
117                         } catch(Exception e) {
118                                 throw new HttpException("Parse error:" + file, e);
119                         } finally {
120                                 if (fStream != null)
121                                         fStream.Close();
122                         }
123
124                         if (list.Count == 0)
125                                 throw new HttpException ("No advertisements found");
126
127                         AdRecord [] adsArray = new AdRecord [list.Count];
128                         int count = list.Count;
129                         for (int i = 0; i < count; i++)
130                                 adsArray [i] = new AdRecord ((IDictionary) list [i]);
131
132                         return adsArray;
133                 }
134
135                 AdRecord [] GetData (string file)
136                 {
137                         string physPath = MapPathSecure (file);
138                         string AdKey = "AdRotatorCache: " + physPath;
139                         fileDirectory = UrlUtils.GetDirectory (UrlUtils.Combine (TemplateSourceDirectory, file));
140                         Cache cache = HttpRuntime.Cache;
141                         AdRecord[] records = (AdRecord[]) cache [AdKey];
142                         if (records == null) {
143                                 records = LoadAdFile (physPath);
144                                 cache.Insert (AdKey, records, new CacheDependency (physPath));
145                         }
146
147                         return records;
148                 }
149
150                 IDictionary SelectAd ()
151                 {
152                         AdRecord[] records = GetData (AdvertisementFile);
153                         if (records == null || records.Length ==0)
154                                 return null;
155
156                         int impressions = 0;
157                         int rlength = records.Length;
158                         for (int i=0 ; i < rlength; i++) {
159                                 if (IsAdMatching (records [i]))
160                                         impressions += records [i].Hits;
161                         }
162
163                         if (impressions == 0)
164                                 return null;
165
166                         if (random == null)
167                                 random = new Random ();
168
169                         int rnd = random.Next (impressions) + 1;
170                         int counter = 0;
171                         int index = 0;
172                         for (int i = 0; i < rlength; i++) {
173                                 if(IsAdMatching(records[i])) {
174                                         if (rnd <= (counter + records [i].Hits)) {
175                                                 index = i;
176                                                 break;
177                                         }
178                                         counter += records [i].Hits;
179                                 }
180                         }
181
182                         return records [index].Properties;
183                 }
184
185                 private bool IsAdMatching (AdRecord currAd)
186                 {
187                         if (KeywordFilter != String.Empty)
188                                 return (0 == String.Compare (currAd.Keyword, KeywordFilter, true));
189
190                         return true;
191                 }
192
193                 private string ResolveAdUrl (string relativeUrl)
194                 {
195                         if (relativeUrl.Length==0 || !UrlUtils.IsRelativeUrl (relativeUrl))
196                                 return relativeUrl;
197
198                         string fullUrl;
199                         if (fileDirectory != null)
200                                 fullUrl = fileDirectory;
201                         else
202                                 fullUrl = TemplateSourceDirectory;
203
204                         if (fullUrl.Length == 0)
205                                 return relativeUrl;
206
207                         return UrlUtils.Combine (fullUrl, relativeUrl);
208                 }
209
210                 [WebCategory("Action")]
211                 [WebSysDescription("AdRotator_OnAdCreated")]
212                 public event AdCreatedEventHandler AdCreated {
213                         add { Events.AddHandler (AdCreatedEvent, value); }
214                         remove { Events.RemoveHandler (AdCreatedEvent, value); }
215                 }
216
217                 [Bindable(true)]
218                 [DefaultValue("")]
219                 [Editor ("System.Web.UI.Design.XmlUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
220                 [WebCategory("Behaviour")]
221                 [WebSysDescription("AdRotator_AdvertisementFile")]
222                 public string AdvertisementFile {
223                         get { return ((advertisementFile != null) ? advertisementFile : ""); }
224                         set { advertisementFile = value; }
225                 }
226
227                 [Browsable (false), EditorBrowsable (EditorBrowsableState.Never)]
228                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
229                 public override FontInfo Font {
230                         get { return base.Font; }
231                 }
232
233                 [Bindable(true)]
234                 [DefaultValue("")]
235                 [WebCategory("Behaviour")]
236                 [WebSysDescription("AdRotator_KeywordFilter")]
237                 public string KeywordFilter {
238                         get {
239                                 object o = ViewState ["KeywordFilter"];
240                                 if (o != null)
241                                         return (string) o;
242
243                                 return String.Empty;
244                         }
245                         set {
246                                 if(value != null)
247                                         ViewState ["KeywordFilter"] = value.Trim ();
248                         }
249                 }
250
251                 [Bindable(true)]
252                 [DefaultValue("")]
253                 [TypeConverter(typeof(TargetConverter))]
254                 [WebCategory("Behaviour")]
255                 [WebSysDescription("AdRotator_Target")]
256                 public string Target {
257                         get {
258                                 object o = ViewState ["Target"];
259                                 if (o != null)
260                                         return (string) o;
261
262                                 return "_top";
263                         }
264                         set {
265                                 ViewState["Target"] = value;
266                         }
267                 }
268
269                 protected override ControlCollection CreateControlCollection ()
270                 {
271                         return new EmptyControlCollection (this);
272                 }
273
274                 protected virtual void OnAdCreated (AdCreatedEventArgs e)
275                 {
276                         if (Events == null)
277                                 return;
278
279                         AdCreatedEventHandler aceh = (AdCreatedEventHandler) Events [AdCreatedEvent];
280                         if (aceh != null)
281                                 aceh (this, e);
282                 }
283
284                 protected override void OnPreRender (EventArgs e)
285                 {
286                         if(AdvertisementFile == String.Empty)
287                                 return;
288
289                         AdCreatedEventArgs acea = new AdCreatedEventArgs (SelectAd ());
290                         OnAdCreated (acea);
291                         imageUrl = acea.ImageUrl;
292                         navigateUrl = acea.NavigateUrl;
293                         alternateText = acea.AlternateText;
294                 }
295
296                 protected override void Render (HtmlTextWriter writer)
297                 {
298                         HyperLink hLink = new HyperLink ();
299                         Image adImage = new Image();
300                         foreach (string current in Attributes.Keys)
301                                 hLink.Attributes [current] = Attributes [current];
302
303                         if (ID != null && ID.Length > 0)
304                                 hLink.ID = ID;
305
306                         hLink.Target = Target;
307                         hLink.AccessKey = AccessKey;
308                         hLink.Enabled  = Enabled;
309                         hLink.TabIndex = TabIndex;
310                         if (navigateUrl != null && navigateUrl.Length != 0)
311                                 hLink.NavigateUrl = ResolveAdUrl (navigateUrl);
312
313                         hLink.RenderBeginTag (writer);
314                         if (ControlStyleCreated)
315                                 adImage.ApplyStyle(ControlStyle);
316
317                         if(imageUrl!=null && imageUrl.Length > 0)
318                                 adImage.ImageUrl = ResolveAdUrl (imageUrl);
319
320                         adImage.AlternateText = alternateText;
321                         adImage.ToolTip = ToolTip;
322                         adImage.RenderControl (writer);
323                         hLink.RenderEndTag (writer);
324                 }
325
326                 class AdRecord
327                 {
328                         public IDictionary Properties;
329                         public int Hits; // or impressions or clicks
330                         public string Keyword;
331
332                         public AdRecord (IDictionary adProps)
333                         {
334                                 this.Properties = adProps;
335                                 Keyword = Properties ["Keyword"] as string;
336                                 if (Keyword == null)
337                                         Keyword = "";
338
339                                 string imp = Properties ["Impressions"] as string;
340                                 Hits = 1;
341                                 if (imp != null) {
342                                         try {
343                                                 Hits = Int32.Parse (imp);
344                                         } catch {
345                                         }
346                                 }
347                         }
348                 }
349         }
350 }
351