2004-05-26 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[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 using System;
15 using System.IO;
16 using System.Collections;
17 using System.Collections.Specialized;
18 using System.Web;
19 using System.Web.Caching;
20 using System.Web.UI;
21 using System.Xml;
22 using System.Web.Util;
23 using System.ComponentModel;
24 using System.ComponentModel.Design;
25
26 namespace System.Web.UI.WebControls
27 {
28         [DefaultEvent("AdCreated")]
29         [DefaultProperty("AdvertisementFile")]
30         [Designer ("System.Web.UI.Design.WebControls.AdRotatorDesigner, " + Consts.AssemblySystem_Design, typeof (IDesigner))]
31         [ToolboxData("<{0}:AdRotator runat=\"server\" Height=\"60px\" "
32         + "Width=\"468\"></{0}:AdRotator>")]
33         public class AdRotator: WebControl
34         {
35                 string advertisementFile;
36                 static readonly object AdCreatedEvent = new object();
37
38                 // Will be set values during (On)PreRender-ing
39                 string alternateText;
40                 string imageUrl;
41                 string navigateUrl;
42                 string fileDirectory;
43                 Random random;
44
45                 public AdRotator ()
46                 {
47                         advertisementFile = "";
48                         fileDirectory     = null;
49                 }
50
51                 AdRecord[] LoadAdFile (string file)
52                 {
53                         Stream fStream;
54                         try {
55                                 fStream = new FileStream (file, FileMode.Open, FileAccess.Read, FileShare.Read);
56                         } catch (Exception e) {
57                                 throw new HttpException("AdRotator: Unable to open file", e);
58                         }
59
60                         ArrayList list = new ArrayList ();
61                         try {
62                                 IDictionary hybridDict = null;
63                                 XmlDocument document = new XmlDocument ();
64                                 document.Load (fStream);
65
66                                 XmlElement docElem = document.DocumentElement;
67
68                                 if (docElem == null)
69                                         throw new HttpException ("No advertisements found");
70
71                                 if (docElem.LocalName != "Advertisements")
72                                         throw new HttpException ("No advertisements found: invalid document element");
73
74                                 XmlNode node = docElem.FirstChild;
75                                 while (node != null) {
76                                         if (node.LocalName == "Ad") {
77                                                 XmlNode innerNode = node.FirstChild;
78                                                 while (innerNode != null) {
79                                                         if (node.NodeType == XmlNodeType.Element) {
80                                                                 if (hybridDict == null)
81                                                                         hybridDict = new HybridDictionary ();
82
83                                                                 hybridDict.Add (innerNode.LocalName, innerNode.InnerText);
84                                                         }
85                                                         innerNode = innerNode.NextSibling;
86                                                 }
87
88                                                 if (hybridDict != null) {
89                                                         list.Add (hybridDict);
90                                                         hybridDict = null;
91                                                 }
92                                         }
93                                         node = node.NextSibling;
94                                 }
95
96                         } catch(Exception e) {
97                                 throw new HttpException("Parse error:" + file, e);
98                         } finally {
99                                 if (fStream != null)
100                                         fStream.Close();
101                         }
102
103                         if (list.Count == 0)
104                                 throw new HttpException ("No advertisements found");
105
106                         AdRecord [] adsArray = new AdRecord [list.Count];
107                         int count = list.Count;
108                         for (int i = 0; i < count; i++)
109                                 adsArray [i] = new AdRecord ((IDictionary) list [i]);
110
111                         return adsArray;
112                 }
113
114                 AdRecord [] GetData (string file)
115                 {
116                         string physPath = MapPathSecure (file);
117                         string AdKey = "AdRotatorCache: " + physPath;
118                         fileDirectory = UrlUtils.GetDirectory (UrlUtils.Combine (TemplateSourceDirectory, file));
119                         Cache cache = HttpRuntime.Cache;
120                         AdRecord[] records = (AdRecord[]) cache [AdKey];
121                         if (records == null) {
122                                 records = LoadAdFile (physPath);
123                                 cache.Insert (AdKey, records, new CacheDependency (physPath));
124                         }
125
126                         return records;
127                 }
128
129                 IDictionary SelectAd ()
130                 {
131                         AdRecord[] records = GetData (AdvertisementFile);
132                         if (records == null || records.Length ==0)
133                                 return null;
134
135                         int impressions = 0;
136                         int rlength = records.Length;
137                         for (int i=0 ; i < rlength; i++) {
138                                 if (IsAdMatching (records [i]))
139                                         impressions += records [i].Hits;
140                         }
141
142                         if (impressions == 0)
143                                 return null;
144
145                         if (random == null)
146                                 random = new Random ();
147
148                         int rnd = random.Next (impressions) + 1;
149                         int counter = 0;
150                         int index = 0;
151                         for (int i = 0; i < rlength; i++) {
152                                 if(IsAdMatching(records[i])) {
153                                         if (rnd <= (counter + records [i].Hits)) {
154                                                 index = i;
155                                                 break;
156                                         }
157                                         counter += records [i].Hits;
158                                 }
159                         }
160
161                         return records [index].Properties;
162                 }
163
164                 private bool IsAdMatching (AdRecord currAd)
165                 {
166                         if (KeywordFilter != String.Empty)
167                                 return (0 == String.Compare (currAd.Keyword, KeywordFilter, true));
168
169                         return true;
170                 }
171
172                 private string ResolveAdUrl (string relativeUrl)
173                 {
174                         if (relativeUrl.Length==0 || !UrlUtils.IsRelativeUrl (relativeUrl))
175                                 return relativeUrl;
176
177                         string fullUrl;
178                         if (fileDirectory != null)
179                                 fullUrl = fileDirectory;
180                         else
181                                 fullUrl = TemplateSourceDirectory;
182
183                         if (fullUrl.Length == 0)
184                                 return relativeUrl;
185
186                         return UrlUtils.Combine (fullUrl, relativeUrl);
187                 }
188
189                 [WebCategory("Action")]
190                 [WebSysDescription("AdRotator_OnAdCreated")]
191                 public event AdCreatedEventHandler AdCreated {
192                         add { Events.AddHandler (AdCreatedEvent, value); }
193                         remove { Events.RemoveHandler (AdCreatedEvent, value); }
194                 }
195
196                 [Bindable(true)]
197                 [DefaultValue("")]
198                 [Editor ("System.Web.UI.Design.XmlUrlEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))]
199                 [WebCategory("Behaviour")]
200                 [WebSysDescription("AdRotator_AdvertisementFile")]
201                 public string AdvertisementFile {
202                         get { return ((advertisementFile != null) ? advertisementFile : ""); }
203                         set { advertisementFile = value; }
204                 }
205
206                 [Browsable (false), EditorBrowsable (EditorBrowsableState.Never)]
207                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
208                 public override FontInfo Font {
209                         get { return base.Font; }
210                 }
211
212                 [Bindable(true)]
213                 [DefaultValue("")]
214                 [WebCategory("Behaviour")]
215                 [WebSysDescription("AdRotator_KeywordFilter")]
216                 public string KeywordFilter {
217                         get {
218                                 object o = ViewState ["KeywordFilter"];
219                                 if (o != null)
220                                         return (string) o;
221
222                                 return String.Empty;
223                         }
224                         set {
225                                 if(value != null)
226                                         ViewState ["KeywordFilter"] = value.Trim ();
227                         }
228                 }
229
230                 [Bindable(true)]
231                 [DefaultValue("")]
232                 [TypeConverter(typeof(TargetConverter))]
233                 [WebCategory("Behaviour")]
234                 [WebSysDescription("AdRotator_Target")]
235                 public string Target {
236                         get {
237                                 object o = ViewState ["Target"];
238                                 if (o != null)
239                                         return (string) o;
240
241                                 return "_top";
242                         }
243                         set {
244                                 ViewState["Target"] = value;
245                         }
246                 }
247
248                 protected override ControlCollection CreateControlCollection ()
249                 {
250                         return new EmptyControlCollection (this);
251                 }
252
253                 protected virtual void OnAdCreated (AdCreatedEventArgs e)
254                 {
255                         if (Events == null)
256                                 return;
257
258                         AdCreatedEventHandler aceh = (AdCreatedEventHandler) Events [AdCreatedEvent];
259                         if (aceh != null)
260                                 aceh (this, e);
261                 }
262
263                 protected override void OnPreRender (EventArgs e)
264                 {
265                         if(AdvertisementFile == String.Empty)
266                                 return;
267
268                         AdCreatedEventArgs acea = new AdCreatedEventArgs (SelectAd ());
269                         OnAdCreated (acea);
270                         imageUrl = acea.ImageUrl;
271                         navigateUrl = acea.NavigateUrl;
272                         alternateText = acea.AlternateText;
273                 }
274
275                 protected override void Render (HtmlTextWriter writer)
276                 {
277                         HyperLink hLink = new HyperLink ();
278                         Image adImage = new Image();
279                         foreach (string current in Attributes.Keys)
280                                 hLink.Attributes [current] = Attributes [current];
281
282                         if (ID != null && ID.Length > 0)
283                                 hLink.ID = ID;
284
285                         hLink.Target = Target;
286                         hLink.AccessKey = AccessKey;
287                         hLink.Enabled  = Enabled;
288                         hLink.TabIndex = TabIndex;
289                         if (navigateUrl != null && navigateUrl.Length != 0)
290                                 hLink.NavigateUrl = ResolveAdUrl (navigateUrl);
291
292                         hLink.RenderBeginTag (writer);
293                         if (ControlStyleCreated)
294                                 adImage.ApplyStyle(ControlStyle);
295
296                         if(imageUrl!=null && imageUrl.Length > 0)
297                                 adImage.ImageUrl = ResolveAdUrl (imageUrl);
298
299                         adImage.AlternateText = alternateText;
300                         adImage.ToolTip = ToolTip;
301                         adImage.RenderControl (writer);
302                         hLink.RenderEndTag (writer);
303                 }
304
305                 class AdRecord
306                 {
307                         public IDictionary Properties;
308                         public int Hits; // or impressions or clicks
309                         public string Keyword;
310
311                         public AdRecord (IDictionary adProps)
312                         {
313                                 this.Properties = adProps;
314                                 Keyword = Properties ["Keyword"] as string;
315                                 if (Keyword == null)
316                                         Keyword = "";
317
318                                 string imp = Properties ["Impressions"] as string;
319                                 Hits = 1;
320                                 if (imp != null) {
321                                         try {
322                                                 Hits = Int32.Parse (imp);
323                                         } catch {
324                                         }
325                                 }
326                         }
327                 }
328         }
329 }
330