~ubuntu-branches/ubuntu/jaunty/gnome-do-plugins/jaunty-proposed

« back to all changes in this revision

Viewing changes to BundledLibraries/libgoogle-data-mono-1.4.0.2/src/core/feedmodel.cs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane, Daniel T Chen, Iain Lane
  • Date: 2009-03-18 00:40:51 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090318004051-ujn1ja3kiu3ky7ru
Tags: 0.8.1.3+dfsg-0ubuntu1
[ Daniel T Chen ]
* New upstream release (LP: #344578)
  + Banshee plugin goes crazy if banshee isn't loaded first
    (LP: #289802)
  + gnome-do gCalculate plugin fails to display "times" symbol
    (LP: #274252)
  + Banshee-1 fails to build in Mono 2.0 (LP: #309188)
  + Pidgin 2.5.4 has incompatible dbus interface. s/uint/int/
    (LP: #314927)
  + Pidgin plugin hangs opening a chat if pidgin is unresponsive
    (LP: #315565)
  + twitter plugin still reports friend updates even when
    deactivated (LP: #317674)
  + Misspelling in microblogging plugin confirmation message
    (LP: #319433)
  + make install uses mdtool, but configure doesn't check for it
    (LP: #322951)
  + Virtualbox Icon in 2.10 are broken because of a new
    specification (LP: #323902)
  + Google Maps Plugin shouldn't always use route (LP: #324271)
  + Fix for Google Maps when using newlines and other special
    characters (LP: #324667)
  + VirtualBox failed to load icon (LP: #325712)
  + 'Read Man Pages' plugin makes Gnome-Do unresponsive
    (LP: #325935)
  + Search returns broken URLs (LP: #327855)
  + Default action for SSH hosts is "open" (LP: #328236)
  + Files and Folders Configuration doesn't use standard buttons
    (LP: #328236)
  + Window manager maximize action should focus if window is not
    currently focused (LP: #258893)
  + Locate plugin has no error message (LP: #262360)
  + Wishlist: Let user specify files and folders to ignore
    (LP: #263177)
  + ts-client plugin doesn't index subdirectories (LP: #322352)
  + Max 3000 items in Files and Folders plugin (LP: #324105)
  + putty cannot find host when running from gnome do
    (LP: #324282)
  + locate plugin with globbing (LP: #334798)
  + Twitter plugin encountered an error in UpdateFriends
    (LP: #317575)
  + gnome-terminal profiles no longer work (LP: #321977)
  + Creating a task using Remember the Milk plugin can fail if
    no task list is specified (LP: #324066)
  + bundled libraries makefile needs destdir (LP: #324704)
  + Typographical error in del.icio.us plugin (LP: #330525)
  + ImageShack fails to upload (LP: #337324)
* debian/copyright
  + Refresh for new upstream version; new plugins added.
* debian/patches/00_dfsg_autofoo.dpatch
  + Update for new upstream version
  + Don't build the YouTube plugin due to removal of shipped
    exes and dlls causing FTBFS
* debian/patches/02_ssh_respect_exec_arg.dpatch
  debian/patches/03_buildsystem_respect_mcs.dpatch
  debian/patches/04_fix_pidgin_dbus_ints.dpatch
  + Drop; fixed upstream

[ Iain Lane ]
* debian/rules: Update repackaging to not delete *.dll; upstream now ships
  source copies of google-gdata meaning we can now enable the Google and
  Youtube plugins.
* debian/patches/00_dfsg_autofoo: Drop, fixed by including and building
  these libs now. 
* debian/copyright: Update with information for google-gdata. 
* debian/patches/04_fix_pidgin_dbus_ints.dpatch: Add left out piece of patch
* debian/control: Bump gnome-do build-dep to require current version. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2006 Google Inc.
 
2
 *
 
3
 * Licensed under the Apache License, Version 2.0 (the "License");
 
4
 * you may not use this file except in compliance with the License.
 
5
 * You may obtain a copy of the License at
 
6
 *
 
7
 *     http://www.apache.org/licenses/LICENSE-2.0
 
8
 *
 
9
 * Unless required by applicable law or agreed to in writing, software
 
10
 * distributed under the License is distributed on an "AS IS" BASIS,
 
11
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
12
 * See the License for the specific language governing permissions and
 
13
 * limitations under the License.
 
14
*/
 
15
 
 
16
 
 
17
using System;
 
18
using System.IO;
 
19
using System.Collections;
 
20
using System.Text;
 
21
using System.Net; 
 
22
using Google.GData.Client;
 
23
using Google.GData.Extensions;
 
24
using System.Collections.Generic;
 
25
using Google.GData.Extensions.AppControl;
 
26
 
 
27
 
 
28
namespace Google.GData.Client
 
29
{
 
30
    //////////////////////////////////////////////////////////////////////
 
31
    /// <summary>a generic Feed class
 
32
    /// </summary> 
 
33
    //////////////////////////////////////////////////////////////////////
 
34
    public class Feed<T> where T: Entry, new()
 
35
    {
 
36
        AtomFeed af;
 
37
        bool paging;
 
38
        int  maximum = -1; 
 
39
        int  numberRetrieved=0; 
 
40
        Service service; 
 
41
        FeedQuery query; 
 
42
 
 
43
 
 
44
        /// <summary>
 
45
        /// default constructor that takes the underlying atomfeed
 
46
        /// </summary>
 
47
        /// <param name="af"></param>
 
48
        public Feed(AtomFeed af)
 
49
        {
 
50
            this.af = af; 
 
51
        }
 
52
 
 
53
        /// <summary>
 
54
        /// constructs a new feed object based on a service and a query
 
55
        /// </summary>
 
56
        /// <param name="service"></param>
 
57
        /// <param name="q"></param>
 
58
        public Feed(Service service, FeedQuery q)
 
59
        {
 
60
            this.service = service;
 
61
            this.query = q; 
 
62
        }
 
63
 
 
64
        /// <summary>
 
65
        /// returns the used feed object
 
66
        /// </summary>
 
67
        /// <returns></returns>
 
68
        public AtomFeed AtomFeed
 
69
        {
 
70
            get
 
71
            {
 
72
                if (this.af == null)
 
73
                {
 
74
                    if (this.service != null && this.query != null)
 
75
                    {
 
76
                        this.af = this.service.Query(query);
 
77
                    }
 
78
                }
 
79
                return this.af;
 
80
            }
 
81
        }
 
82
 
 
83
       /// <summary>
 
84
       /// if set to true will cause the feed to add more data when you iterate over it's entries
 
85
       /// </summary>
 
86
       /// <returns></returns>
 
87
       public bool AutoPaging
 
88
       {
 
89
           get 
 
90
           {
 
91
               return this.paging;
 
92
           }
 
93
           set
 
94
           {
 
95
               this.paging = value;
 
96
           }
 
97
       }
 
98
 
 
99
 
 
100
   
 
101
       /// <summary>
 
102
       /// returns the position in the real feed of the first entry in this feed
 
103
       /// </summary>
 
104
       /// <returns>an int indicating the start in the feed</returns>
 
105
       public int StartIndex
 
106
       {
 
107
           get
 
108
           {
 
109
               if (this.AtomFeed != null)
 
110
               {
 
111
                   return this.AtomFeed.StartIndex;
 
112
               }
 
113
               return -1;  
 
114
           }
 
115
       }
 
116
 
 
117
       /// <summary>
 
118
       /// returns the setup paging size of this feed. If you set AutoPaging to true
 
119
       /// this is the size that is used to get more results
 
120
       /// </summary>
 
121
       /// <returns></returns>
 
122
       public int PageSize
 
123
       {
 
124
           get
 
125
           {
 
126
               if (this.AtomFeed != null)
 
127
               {
 
128
                   return this.AtomFeed.ItemsPerPage;
 
129
               }
 
130
               return -1; 
 
131
           }
 
132
       }
 
133
 
 
134
       /// <summary>
 
135
       /// returns the number of entries the server believes the feed holds
 
136
       /// </summary>
 
137
       /// <returns></returns>
 
138
       public int TotalResults
 
139
       {
 
140
           get
 
141
           {
 
142
               if (this.AtomFeed != null)
 
143
               {
 
144
                   return this.AtomFeed.TotalResults;
 
145
               }
 
146
               return -1; 
 
147
           }
 
148
       }
 
149
 
 
150
 
 
151
       /// <summary>
 
152
       /// the maxium number of entries to be retrieved. This is normally 
 
153
       /// setup using the RequestSettings when the feed is constructed.
 
154
       /// </summary>
 
155
       /// <returns></returns>
 
156
       public int Maximum
 
157
       {
 
158
           get
 
159
           {
 
160
               return this.maximum;
 
161
           }
 
162
           set
 
163
           {
 
164
               this.maximum = value; 
 
165
           }
 
166
       }
 
167
 
 
168
 
 
169
       /**
 
170
       <summary>
 
171
        returns the initial list of entries.This page is the data
 
172
        you got from the Requestobject and will remain constant.
 
173
        Unless you set AutoPaging to true, in that case:
 
174
        This will go back to the server and fetch data again if
 
175
        needed. Example. If you pagesize is 30, you get an initial set of 
 
176
        30 entries. While enumerating, when reaching 30, the code will go 
 
177
        to the server and get the next 30 rows. It will continue to do so
 
178
        until the server reports no more rows available.
 
179
        Note that you should cache the entries returned in a list of your own
 
180
        if you want to access them more than once, as this one does no caching on
 
181
        it's own.
 
182
        </summary>
 
183
         <example>
 
184
                The following code illustrates a possible use of   
 
185
                the <c>Entries</c> property:  
 
186
                <code>    
 
187
                  YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
188
                  YouTubeRequest f = new YouTubeRequest(settings);
 
189
                  Feed&lt;Playlist&gt; feed = f.GetPlaylistsFeed(null);
 
190
                  foreach (Vidoe v in feed.Entries)
 
191
                </code>
 
192
            </example>
 
193
        <returns></returns> 
 
194
        */
 
195
        public IEnumerable<T> Entries
 
196
        {
 
197
            get
 
198
            {
 
199
                bool looping;
 
200
 
 
201
                // if we have iterated once before, we need to reset
 
202
                if (this.numberRetrieved > 0 && this.paging == false && this.service != null)
 
203
                {
 
204
                    this.af = null; 
 
205
                }
 
206
                if (this.AtomFeed == null)
 
207
                    yield break;
 
208
 
 
209
                this.numberRetrieved = 0; 
 
210
 
 
211
                do
 
212
                {
 
213
                    looping = af.NextChunk != null && this.paging == true;
 
214
                    foreach (AtomEntry e in af.Entries)
 
215
                    {
 
216
                        T t = new T();
 
217
                        if (t != null)
 
218
                        {
 
219
                            t.AtomEntry = e; 
 
220
                            this.numberRetrieved++; 
 
221
                            yield return t; 
 
222
                        }
 
223
                        if (this.Maximum > 0 && this.numberRetrieved >= this.Maximum)
 
224
                        {
 
225
                            yield break; 
 
226
                        }
 
227
                    }
 
228
                    if (looping)
 
229
                    {
 
230
                        FeedQuery q = new FeedQuery(this.AtomFeed.NextChunk);
 
231
                        this.af = this.AtomFeed.Service.Query(q);
 
232
                    }
 
233
                } while (looping);
 
234
            }
 
235
        }
 
236
    }
 
237
    //end of public class Feed
 
238
 
 
239
 
 
240
    /// <summary>
 
241
    /// the Entry class is the base class for all Feed of T type feeds
 
242
    /// it encapsulates the AtomEntry
 
243
    /// </summary>
 
244
    /// <returns></returns>
 
245
    public abstract class Entry
 
246
    {
 
247
        private AtomEntry e; 
 
248
 
 
249
        /// <summary>
 
250
        ///  default public constructor, needed for generics. You should not use that one, but use the
 
251
        /// CreateInstance method for the entry you want to create
 
252
        /// </summary>
 
253
        /// <returns></returns>
 
254
        public Entry()
 
255
        {
 
256
        }
 
257
 
 
258
        /// <summary>override for ToString, returns the Entries Title</summary> 
 
259
        public override string ToString()
 
260
        {
 
261
            return this.Title;
 
262
        }
 
263
 
 
264
        /// <summary>
 
265
        /// needs to be subclassed to ensure the creation of the corrent AtomEntry based
 
266
        /// object
 
267
        /// </summary>
 
268
        protected abstract void EnsureInnerObject();
 
269
 
 
270
        /// <summary>
 
271
        ///  the original AtomEntry object that this object is standing in for
 
272
        /// </summary>
 
273
        /// <returns></returns>
 
274
        public AtomEntry AtomEntry
 
275
        {
 
276
            get
 
277
            {
 
278
                return this.e;
 
279
            }
 
280
            set 
 
281
            {
 
282
                this.e = value; 
 
283
            }
 
284
        }
 
285
 
 
286
        /// <summary>
 
287
        /// returns the Id of an entry
 
288
        /// </summary>
 
289
        public string Id
 
290
        {
 
291
            get
 
292
            {
 
293
                EnsureInnerObject();
 
294
                return this.e.Id.AbsoluteUri;
 
295
            }
 
296
            set
 
297
            {
 
298
                EnsureInnerObject();
 
299
                this.e.Id = new AtomId(value);
 
300
            }
 
301
        }
 
302
 
 
303
        /// <summary>
 
304
        /// returns the value of the self uri as a string
 
305
        /// </summary>
 
306
        /// <returns></returns>
 
307
        public string Self
 
308
        {
 
309
            get
 
310
            {
 
311
                EnsureInnerObject();
 
312
                if (this.e.SelfUri != null)
 
313
                {
 
314
                    return this.e.SelfUri.ToString();
 
315
                }
 
316
                return null;
 
317
            }
 
318
        }
 
319
 
 
320
 
 
321
        /// <summary>
 
322
        /// the title of the Entry. 
 
323
        /// </summary>
 
324
        /// <returns></returns>
 
325
        public virtual string Title
 
326
        {
 
327
            get 
 
328
            {
 
329
                EnsureInnerObject();
 
330
                return this.e.Title.Text;
 
331
            }
 
332
            set 
 
333
            {
 
334
                EnsureInnerObject();
 
335
                this.e.Title.Text = value; 
 
336
            }
 
337
        }
 
338
 
 
339
        /// <summary>
 
340
        /// returns the appControl sublement
 
341
        /// </summary>
 
342
        public AppControl AppControl
 
343
        {
 
344
            get
 
345
            {
 
346
                EnsureInnerObject();
 
347
                return this.e.AppControl;
 
348
            }
 
349
            set
 
350
            {
 
351
                EnsureInnerObject();
 
352
                this.e.AppControl = value;
 
353
            }
 
354
        }
 
355
 
 
356
 
 
357
        /// <summary>
 
358
        /// returns the appControl sublement
 
359
        /// </summary>
 
360
        public bool IsDraft
 
361
        {
 
362
            get
 
363
            {
 
364
                EnsureInnerObject(); 
 
365
                return this.e.IsDraft; 
 
366
            }
 
367
        }
 
368
 
 
369
        /// <summary>
 
370
        /// returns true, if the entry has an edit link
 
371
        /// </summary>
 
372
        public bool ReadOnly
 
373
        {
 
374
            get
 
375
            {
 
376
                EnsureInnerObject();
 
377
                return this.e.EditUri == null; 
 
378
            }
 
379
        }
 
380
 
 
381
 
 
382
        /// <summary>
 
383
        ///  returns the first author name in the atom.entry.authors collection
 
384
        /// </summary>
 
385
        /// <returns></returns>
 
386
        public string Author
 
387
        {
 
388
            get
 
389
            {
 
390
                EnsureInnerObject();
 
391
                if (this.e.Authors.Count > 0 && this.e.Authors[0] != null)
 
392
                {
 
393
                    return this.e.Authors[0].Name;
 
394
                }
 
395
                return null;
 
396
            }
 
397
            set
 
398
            {
 
399
                EnsureInnerObject();
 
400
                AtomPerson p = null; 
 
401
                if (this.e.Authors.Count == 0)
 
402
                {
 
403
                    p = new AtomPerson(AtomPersonType.Author);
 
404
                    this.e.Authors.Add(p);
 
405
                }
 
406
                else
 
407
                {
 
408
                    p = this.e.Authors[0];
 
409
                }
 
410
                p.Name = value; 
 
411
            }
 
412
        }
 
413
 
 
414
        /// <summary>
 
415
        /// returns the string representation of the atom.content element
 
416
        /// </summary>
 
417
        /// <returns></returns>
 
418
        public string Content
 
419
        {
 
420
            get
 
421
            {
 
422
                EnsureInnerObject();
 
423
                return this.e.Content.Content;
 
424
            }
 
425
            set
 
426
            {
 
427
                EnsureInnerObject();
 
428
                this.e.Content.Content = value;
 
429
            }
 
430
        }
 
431
 
 
432
        /// <summary>
 
433
        /// returns the string representation of the atom.Summary element
 
434
        /// </summary>
 
435
        /// <returns></returns>
 
436
        public string Summary
 
437
        {
 
438
            get
 
439
            {
 
440
                EnsureInnerObject();
 
441
                return this.e.Summary.Text;
 
442
            }
 
443
            set
 
444
            {
 
445
                EnsureInnerObject();
 
446
                this.e.Summary.Text = value;
 
447
            }
 
448
        }
 
449
 
 
450
        /// <summary>
 
451
        /// just a thin layer on top of the existing updated of the 
 
452
        /// underlying atomentry
 
453
        /// </summary>
 
454
        public DateTime Updated
 
455
        {
 
456
            get
 
457
            {
 
458
                EnsureInnerObject();
 
459
                return this.e.Updated;
 
460
            }
 
461
            set
 
462
            {
 
463
                EnsureInnerObject();
 
464
                this.e.Updated = value;
 
465
            }
 
466
        }
 
467
 
 
468
 
 
469
        /// <summary>
 
470
        /// this returns the batch data for the inner atom object
 
471
        /// </summary>
 
472
        /// <returns></returns>
 
473
        public GDataBatchEntryData BatchData
 
474
        {
 
475
            get
 
476
            {
 
477
                EnsureInnerObject();
 
478
                return this.e.BatchData;
 
479
            }
 
480
            set
 
481
            {
 
482
                EnsureInnerObject();
 
483
                this.e.BatchData = value;
 
484
            }
 
485
        }
 
486
 
 
487
    }
 
488
 
 
489
   
 
490
    /// <summary>
 
491
    /// Base requestsettings class. Takes credentials, applicationsname
 
492
    /// and supports pagesizes and autopaging. This class is used to initialize a 
 
493
    /// <seealso cref="FeedRequest&lt;T&gt;"/> object.
 
494
    /// </summary>
 
495
    /// <returns></returns>
 
496
    public class RequestSettings
 
497
    {
 
498
        private string applicationName;
 
499
        private GDataCredentials credentials; 
 
500
        private string authSubToken; 
 
501
        private int pageSize = -1;
 
502
        private int max = -1; 
 
503
        private bool autoPage;
 
504
        private int timeout = -1; 
 
505
 
 
506
        /// <summary>
 
507
        /// an unauthenticated use case
 
508
        /// </summary>
 
509
        /// <param name="applicationName"></param>
 
510
        /// <returns></returns>
 
511
        public RequestSettings(string applicationName)
 
512
        {
 
513
            this.applicationName = applicationName;
 
514
        }
 
515
 
 
516
        /// <summary>
 
517
        ///  a constructor for client login use cases
 
518
        /// </summary>
 
519
        /// <param name="applicationName">The name of the application</param>
 
520
        /// <param name="userName">the user name</param>
 
521
        /// <param name="passWord">the password</param>
 
522
        /// <returns></returns>
 
523
        public RequestSettings(string applicationName, string userName, string passWord)
 
524
        {
 
525
            this.applicationName = applicationName;
 
526
            this.credentials = new GDataCredentials(userName, passWord);
 
527
        }
 
528
 
 
529
        /// <summary>
 
530
        ///  a constructor for client login use cases
 
531
        /// </summary>
 
532
        /// <param name="applicationName">The name of the application</param>
 
533
        /// <param name="credentials">the user credentials</param>
 
534
        /// <returns></returns>
 
535
        public RequestSettings(string applicationName, GDataCredentials credentials)
 
536
        {
 
537
            this.applicationName = applicationName;
 
538
            this.credentials = credentials;
 
539
        }
 
540
 
 
541
 
 
542
        /// <summary>
 
543
        /// a constructor for a web application authentication scenario
 
544
        /// </summary>
 
545
        /// <param name="applicationName"></param>
 
546
        /// <param name="authSubToken"></param>
 
547
        /// <returns></returns>
 
548
        public RequestSettings(string applicationName, string authSubToken)
 
549
        {
 
550
            this.applicationName = applicationName;
 
551
            this.authSubToken = authSubToken; 
 
552
        }
 
553
 
 
554
 
 
555
        /// <summary>
 
556
        /// returns the Credentials in case of a client login scenario
 
557
        /// </summary>
 
558
        /// <returns></returns>
 
559
        public GDataCredentials Credentials
 
560
        {
 
561
            get
 
562
            {
 
563
                return this.credentials;
 
564
            }
 
565
        }
 
566
 
 
567
        /// <summary>
 
568
        /// returns the authsub token to use for a webapplication scenario
 
569
        /// </summary>
 
570
        /// <returns></returns>
 
571
        public string AuthSubToken
 
572
        {
 
573
            get
 
574
            {
 
575
                return this.authSubToken;
 
576
            }
 
577
        }
 
578
 
 
579
        /// <summary>
 
580
        /// returns the application name
 
581
        /// </summary>
 
582
        /// <returns></returns>
 
583
        public string Application
 
584
        {
 
585
            get
 
586
            {
 
587
                return this.applicationName;
 
588
            }
 
589
        }
 
590
 
 
591
        /// <summary>
 
592
        /// the pagesize specifies how many entries should be retrieved per call. If not set, 
 
593
        /// the server default will be used. Set it either to -1 (for default) or any value &gt; 0
 
594
        /// to set the pagesize to something the server should honor. Note, that this set's the 
 
595
        /// max-results parameter on the query, and the server is free to ignore that and give you less 
 
596
        /// entries than you have requested. 
 
597
        /// </summary>
 
598
        ///  <example>
 
599
        ///         The following code illustrates a possible use of   
 
600
        ///          the <c>PageSize</c> property:  
 
601
        ///          <code>    
 
602
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
603
        ///            settings.PageSize = 50; 
 
604
        ///  </code>
 
605
        ///  </example>
 
606
        /// <returns></returns>
 
607
        public int PageSize
 
608
        {
 
609
            get
 
610
            {
 
611
                return this.pageSize;
 
612
            }
 
613
            set
 
614
            {
 
615
                this.pageSize = value;
 
616
            }
 
617
        }
 
618
 
 
619
        /// <summary>
 
620
        /// AutoPaging specifies if a feed iterator should return to the server to fetch more data 
 
621
        /// automatically. If set to false, a loop over feed.Entries will stop when the currently 
 
622
        /// fetched set of data reaches it's end.  This is false by default. <seealso cref="RequestSettings.Maximum"/>
 
623
        /// 
 
624
        /// </summary>
 
625
        ///  <example>
 
626
        ///         The following code illustrates a possible use of   
 
627
        ///          the <c>AutoPaging</c> property:  
 
628
        ///          <code>    
 
629
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
630
        ///            settings.AutoPaging = true; 
 
631
        ///  </code>
 
632
        ///  </example>
 
633
        /// <returns></returns>
 
634
        public bool AutoPaging
 
635
        {
 
636
            get
 
637
            {
 
638
                return this.autoPage;
 
639
            }
 
640
            set
 
641
            {
 
642
                this.autoPage = value; 
 
643
            }
 
644
        }
 
645
 
 
646
        /// <summary>
 
647
        /// the Maximum specifies how many entries should be retrieved in total. This works together with 
 
648
        /// <seealso cref="RequestSettings.AutoPaging"/>. If set, AutoPaging of a feed will stop when the 
 
649
        /// specified amount of entries was iterated over. If Maximum is smaller than  PageSize (<seealso cref="RequestSettings.PageSize"/>), 
 
650
        ///  an exception is thrown. The default is -1 (ignored). 
 
651
        /// </summary>
 
652
        ///  <example>
 
653
        ///         The following code illustrates a possible use of   
 
654
        ///          the <c>Maximum</c> property:  
 
655
        ///          <code>    
 
656
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
657
        ///            settings.PageSize = 50; 
 
658
        ///            settings.AutoPaging = true;
 
659
        ///            settings.Maximum = 2000; 
 
660
        ///  </code>
 
661
        ///  </example>
 
662
        /// <returns></returns>
 
663
        public int Maximum
 
664
        {
 
665
            get
 
666
            {
 
667
                return this.max;
 
668
            }
 
669
            set
 
670
            {
 
671
                if (value < this.PageSize)
 
672
                {
 
673
                    throw new ArgumentException("Maximum must be greater or equal to PageSize"); 
 
674
                }
 
675
                this.max = value;
 
676
            }
 
677
        }
 
678
 
 
679
 
 
680
        /// <summary>get's and set's the Timeout property used for the created
 
681
        /// HTTPRequestObject in milliseconds. if you set it to -1 it will stick 
 
682
        /// with the default of the HTPPRequestObject. From MSDN:
 
683
        /// The number of milliseconds to wait before the request times out. 
 
684
        /// The default is 100,000 milliseconds (100 seconds).</summary>   
 
685
        ///  <example>
 
686
        ///         The following code illustrates a possible use of   
 
687
        ///          the <c>Timeout</c> property:  
 
688
        ///          <code>    
 
689
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
690
        ///            settings.Timout = 10000000;
 
691
        ///  </code>
 
692
        ///  </example>
 
693
        /// <returns></returns>
 
694
        public int Timeout
 
695
        {
 
696
            get
 
697
            {
 
698
                return this.timeout;
 
699
            }
 
700
            set
 
701
            {
 
702
                this.timeout = value;
 
703
            }
 
704
        }
 
705
    }
 
706
 
 
707
 
 
708
    /// <summary>
 
709
    /// the enum used for Get of T requests
 
710
    /// </summary>
 
711
    public enum FeedRequestType
 
712
    {
 
713
        /// <summary>
 
714
        /// returns the next feed chunk if there is more data
 
715
        /// </summary>
 
716
        Next,
 
717
        /// <summary>
 
718
        /// returns the previous feed chunk if there is data before
 
719
        /// </summary>
 
720
        Prev,
 
721
        /// <summary>
 
722
        /// refreshes the actual feed chunk by going to the server and retrieving it again
 
723
        /// </summary>
 
724
        Refresh
 
725
    }
 
726
 
 
727
 
 
728
    /// <summary>
 
729
    /// base class for Request objects.
 
730
    /// </summary>
 
731
    /// <returns></returns>
 
732
    public abstract class FeedRequest<T> where T : Service
 
733
    {
 
734
        private RequestSettings settings;
 
735
        private T atomService; 
 
736
 
 
737
 
 
738
       
 
739
 
 
740
        /// <summary>
 
741
        /// default constructor based on a RequestSettings object
 
742
        /// </summary>
 
743
        /// <param name="settings"></param>
 
744
        public FeedRequest(RequestSettings settings)
 
745
        {
 
746
            this.settings = settings; 
 
747
        }
 
748
 
 
749
        /// <summary>
 
750
        /// prepares the created service based on the settings 
 
751
        /// </summary>
 
752
        protected void PrepareService()
 
753
        {
 
754
            PrepareService(this.atomService);
 
755
        }
 
756
 
 
757
        /// <summary>
 
758
        /// prepares the passed in service by setting the authentication credentials and the timeout settings
 
759
        /// </summary>
 
760
        /// <param name="s"></param>
 
761
        protected void PrepareService(Service s)
 
762
        {
 
763
            if (settings.Credentials != null)
 
764
            {
 
765
                s.Credentials = settings.Credentials;
 
766
            }
 
767
#if WindowsCE || PocketPC
 
768
#else
 
769
            if (settings.AuthSubToken != null)
 
770
            {
 
771
                GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory(s.ServiceIdentifier, settings.Application);
 
772
                authFactory.UserAgent = authFactory.UserAgent + "--IEnumerable";
 
773
                authFactory.Token = settings.AuthSubToken; 
 
774
                s.RequestFactory = authFactory;
 
775
            }
 
776
            else 
 
777
            {
 
778
                GDataGAuthRequestFactory authFactory = s.RequestFactory as GDataGAuthRequestFactory;
 
779
                if (authFactory != null)
 
780
                {
 
781
                    authFactory.UserAgent = authFactory.UserAgent + "--IEnumerable";
 
782
                }
 
783
            }
 
784
 
 
785
            if (settings.Timeout != -1)
 
786
            {
 
787
                GDataRequestFactory f  = s.RequestFactory as GDataRequestFactory;
 
788
                if (f != null)
 
789
                {
 
790
                    f.Timeout = settings.Timeout;
 
791
                }
 
792
            }
 
793
#endif
 
794
        }
 
795
 
 
796
        /// <summary>
 
797
        /// creates a query object and set's it up based on the settings object.
 
798
        /// </summary>
 
799
        /// <typeparam name="Y"></typeparam>
 
800
        /// <param name="uri"></param>
 
801
        /// <returns></returns>
 
802
        protected Y PrepareQuery<Y>(string uri) where Y: FeedQuery, new()
 
803
        {
 
804
            Y query = new Y(); 
 
805
            query.BaseAddress = uri; 
 
806
 
 
807
            PrepareQuery(query);
 
808
            return query; 
 
809
        }
 
810
 
 
811
        /// <summary>
 
812
        /// prepares the passed in query objects properties based on the settings
 
813
        /// </summary>
 
814
        /// <param name="q"></param>
 
815
        protected void PrepareQuery(FeedQuery q)
 
816
        {
 
817
            if (this.settings.PageSize != -1)
 
818
            {
 
819
                q.NumberToRetrieve = this.settings.PageSize; 
 
820
            }
 
821
        }
 
822
 
 
823
        /// <summary>
 
824
        /// creates a feed of Y object based on the query and the settings
 
825
        /// </summary>
 
826
        /// <typeparam name="Y"></typeparam>
 
827
        /// <param name="q"></param>
 
828
        /// <returns></returns>
 
829
        protected virtual Feed<Y> PrepareFeed<Y>(FeedQuery q) where Y : Entry, new()
 
830
        {
 
831
             // AtomFeed feed = this.atomService.Query(q);
 
832
             // Feed<Y> f = new Feed<Y>(feed);
 
833
             Feed<Y> f = new Feed<Y>(this.atomService, q);
 
834
             f.AutoPaging = this.settings.AutoPaging;
 
835
             f.Maximum   = this.settings.Maximum;
 
836
             return f;
 
837
        }
 
838
 
 
839
        /// <summary>
 
840
        /// gets a feed object of type T
 
841
        /// </summary>
 
842
        /// <typeparam name="Y"></typeparam>
 
843
        /// <param name="q"></param>
 
844
        /// <returns></returns>
 
845
        public Feed<Y> Get<Y>(FeedQuery q) where Y: Entry, new()
 
846
        {
 
847
            return PrepareFeed<Y>(q);  
 
848
        }
 
849
 
 
850
        /// <summary>
 
851
        /// gets a feed object of type T
 
852
        /// </summary>
 
853
        /// <typeparam name="Y"></typeparam>
 
854
        /// <param name="uri">The Uri to retrieve</param>
 
855
        /// <returns></returns>
 
856
        public Feed<Y> Get<Y>(Uri uri) where Y : Entry, new()
 
857
        {
 
858
            FeedQuery q = new FeedQuery(uri.AbsoluteUri);
 
859
            return PrepareFeed<Y>(q);
 
860
        }
 
861
 
 
862
 
 
863
        /// <summary>
 
864
        /// returns a new feed based on the operation passed in.  This is useful if you either do not use
 
865
        /// autopaging, or want to move to previous parts of the feed, or get a refresh of the current feed
 
866
        /// </summary>
 
867
        ///  <example>
 
868
        ///         The following code illustrates a possible use of   
 
869
        ///          the <c>Get</c> method:  
 
870
        ///          <code>    
 
871
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
872
        ///            YouTubeRequest f = new YouTubeRequest(settings);
 
873
        ///             Feed&lt;Playlist&gt; feed = f.GetPlaylistsFeed(null);
 
874
        ///             Feed&lt;Playlist&gt; next = f.Get&lt;Playlist&gt;(feed, FeedRequestType.Next);
 
875
        ///  </code>
 
876
        ///  </example>
 
877
        /// <param name="feed">the original feed</param>
 
878
        /// <param name="operation">an requesttype to indicate what to retrieve</param>
 
879
        /// <returns></returns>
 
880
        public Feed<Y> Get<Y>(Feed<Y> feed, FeedRequestType operation) where Y: Entry, new()
 
881
        {
 
882
            Feed<Y> f = null; 
 
883
            string spec = null; 
 
884
 
 
885
            if (feed == null)
 
886
            {
 
887
                throw new ArgumentNullException("feed was null");
 
888
            }
 
889
 
 
890
            if (feed.AtomFeed == null)
 
891
            {
 
892
                throw new ArgumentNullException("feed.AtomFeed was null");
 
893
            }
 
894
 
 
895
            switch (operation)
 
896
            {
 
897
                case FeedRequestType.Next:
 
898
                    spec = feed.AtomFeed.NextChunk; 
 
899
                    break;
 
900
                case FeedRequestType.Prev:
 
901
                    spec = feed.AtomFeed.PrevChunk;
 
902
                    break;
 
903
                case FeedRequestType.Refresh:
 
904
                    spec = feed.AtomFeed.Self; 
 
905
                    break;
 
906
            }
 
907
            if (String.IsNullOrEmpty(spec) == false)
 
908
            {
 
909
                FeedQuery q =  new FeedQuery(spec);
 
910
                if (operation == FeedRequestType.Refresh)
 
911
                {
 
912
                    ISupportsEtag ise = feed.AtomFeed as ISupportsEtag;
 
913
                    if (ise != null && ise.Etag != null)
 
914
                    {
 
915
                        q.Etag = ise.Etag;
 
916
                    }
 
917
                }
 
918
                f = PrepareFeed<Y>(q); 
 
919
            }
 
920
 
 
921
            return f; 
 
922
        }
 
923
 
 
924
        /// <summary>
 
925
        /// performs a batch operation. 
 
926
        /// </summary>
 
927
        /// <param name="feed">the original feed, used to find the batch endpoing </param>
 
928
        /// <param name="entries">List of entries of type Y, that are to be batched</param>
 
929
        /// <returns></returns>
 
930
        public Feed<Y> Batch<Y>(List<Y> entries, Feed<Y> feed) where Y : Entry, new()
 
931
        {
 
932
            return this.Batch(entries, feed, GDataBatchOperationType.Default);
 
933
        }
 
934
 
 
935
 
 
936
 
 
937
        /// <summary>
 
938
        /// performs a batch operation. 
 
939
        /// </summary>
 
940
        /// <param name="feed">the original feed, used to find the batch endpoing </param>
 
941
        /// <param name="entries">List of entries of type Y, that are to be batched</param>
 
942
        /// <param name="defaultOperation">indicates the default batch operationtype</param>
 
943
        /// <returns></returns>
 
944
        public Feed<Y> Batch<Y>(List<Y> entries, Feed<Y> feed, GDataBatchOperationType defaultOperation) where Y : Entry, new()
 
945
        {
 
946
            if (feed == null ||
 
947
                feed.AtomFeed == null)
 
948
            {
 
949
                throw new ArgumentNullException("Invalid feed passed in");
 
950
            }
 
951
 
 
952
            if (feed.AtomFeed.Batch == null)
 
953
            {
 
954
                throw new ArgumentException("Feed has no valid batch endpoint");
 
955
            }
 
956
            return this.Batch(entries, new Uri(feed.AtomFeed.Batch), defaultOperation);
 
957
 
 
958
        }
 
959
 
 
960
 
 
961
        /// <summary>
 
962
        /// performs a batch operation. 
 
963
        /// </summary>
 
964
        /// <param name="batchUri">the batch endpoint of the service</param>
 
965
        /// <param name="entries">List of entries of type Y, that are to be batched</param>
 
966
        /// <returns></returns>
 
967
        public Feed<Y> Batch<Y>(List<Y> entries, Uri batchUri, GDataBatchOperationType defaultOperation) where Y: Entry, new()
 
968
        {
 
969
            if (entries.Count > 0)
 
970
            {
 
971
                AtomFeed batchFeed = new AtomFeed(batchUri, null);
 
972
                batchFeed.BatchData = new GDataBatchFeedData();
 
973
                batchFeed.BatchData.Type = defaultOperation;
 
974
                foreach (Y e in entries)
 
975
                {
 
976
                    batchFeed.Entries.Add(e.AtomEntry);
 
977
                }
 
978
                AtomFeed resultFeed = this.Service.Batch(batchFeed, batchUri);
 
979
                Feed<Y> f = new Feed<Y>(resultFeed);
 
980
                return f;
 
981
            }
 
982
            return null;
 
983
        }
 
984
 
 
985
 
 
986
 
 
987
        /// <summary>
 
988
        /// returns the service instance that is used
 
989
        /// </summary>
 
990
        public T Service
 
991
        {
 
992
            get
 
993
            {
 
994
                return this.atomService;
 
995
            }
 
996
            set
 
997
            {
 
998
                this.atomService = value;
 
999
            }
 
1000
        }
 
1001
 
 
1002
 
 
1003
        /// <summary>
 
1004
        /// returns a refreshed version of the entry you passed in, by going back to the server and
 
1005
        /// requesting this resource again
 
1006
        /// </summary>
 
1007
        ///  <example>
 
1008
        ///         The following code illustrates a possible use of   
 
1009
        ///          the <c>Get</c> method:  
 
1010
        ///          <code>    
 
1011
        ///           YouTubeRequestSettings settings = new YouTubeRequestSettings("yourApp", "yourClient", "yourKey", "username", "pwd");
 
1012
        ///            YouTubeRequest f = new YouTubeRequest(settings);
 
1013
        ///             Feed&lt;Playlist&gt; feed = f.GetPlaylistsFeed(null);
 
1014
        ///             Feed&lt;Playlist&gt; next = f.Get&lt;Playlist&gt;(feed, FeedRequestType.Next);
 
1015
        ///  </code>
 
1016
        ///  </example>
 
1017
        /// <param name="entry">the entry to get again</param>
 
1018
        /// <returns></returns>
 
1019
        public Y Retrieve<Y>(Y entry) where Y: Entry, new()
 
1020
        {
 
1021
            if (entry == null)
 
1022
            {
 
1023
                throw new ArgumentNullException("entry was null");
 
1024
            }
 
1025
 
 
1026
            if (entry.AtomEntry == null)
 
1027
            {
 
1028
                throw new ArgumentNullException("entry.AtomEntry was null");
 
1029
            }
 
1030
 
 
1031
            string spec =entry.AtomEntry.SelfUri.ToString();
 
1032
 
 
1033
            if (String.IsNullOrEmpty(spec) == false)
 
1034
            {
 
1035
                FeedQuery q = new FeedQuery(spec);
 
1036
                ISupportsEtag ise = entry.AtomEntry as ISupportsEtag;
 
1037
                if (ise != null && ise.Etag != null)
 
1038
                {
 
1039
                    q.Etag = ise.Etag;
 
1040
                }
 
1041
                return Retrieve<Y>(q); 
 
1042
            }
 
1043
            return null; 
 
1044
        }
 
1045
 
 
1046
        /// <summary>
 
1047
        /// returns a the entry the Uri pointed to
 
1048
        /// </summary>
 
1049
        ///  <example>
 
1050
        /// <param name="entryUri">the Uri of the entry</param>
 
1051
        /// <returns></returns>
 
1052
        public Y Retrieve<Y>(Uri entryUri) where Y : Entry, new()
 
1053
        {
 
1054
            string spec = entryUri.AbsoluteUri;
 
1055
            if (String.IsNullOrEmpty(spec) == false)
 
1056
            {
 
1057
                FeedQuery q = new FeedQuery(spec);
 
1058
                return Retrieve<Y>(q); 
 
1059
            }
 
1060
            return null; 
 
1061
        }
 
1062
 
 
1063
        /// <summary>
 
1064
        /// returns a the entry the Uri pointed to
 
1065
        /// </summary>
 
1066
        ///  <example>
 
1067
        /// <param name="entryUri">the Uri of the entry</param>
 
1068
        /// <returns></returns>
 
1069
        public Y Retrieve<Y>(FeedQuery query) where Y : Entry, new()
 
1070
        {
 
1071
            Feed<Y> f = null;
 
1072
            Y r = null;
 
1073
            f = PrepareFeed<Y>(query);
 
1074
            // this should be a feed of one... 
 
1075
            foreach (Y y in f.Entries)
 
1076
            {
 
1077
                r = y;
 
1078
            }
 
1079
            return r;
 
1080
        }
 
1081
 
 
1082
 
 
1083
        /// <summary>
 
1084
        ///  sends the data back to the server. 
 
1085
        /// </summary>
 
1086
        /// <returns>the reflected entry from the server if any given</returns>
 
1087
        public Y Update<Y>(Y entry) where Y: Entry, new()
 
1088
        {
 
1089
            if (entry == null)
 
1090
                throw new ArgumentNullException("Entry was null");
 
1091
 
 
1092
            if (entry.AtomEntry == null)
 
1093
                throw new ArgumentNullException("Entry.AtomEntry was null");
 
1094
 
 
1095
            Y r = null;
 
1096
            AtomEntry ae = this.Service.Update(entry.AtomEntry);
 
1097
           
 
1098
            if (ae != null)
 
1099
            {
 
1100
                r = new Y();
 
1101
                r.AtomEntry = ae;
 
1102
            }
 
1103
            return r; 
 
1104
        }
 
1105
 
 
1106
        /// <summary>
 
1107
        ///  deletes the Entry from the Server
 
1108
        /// </summary>
 
1109
        public void Delete<Y>(Y entry) where Y : Entry, new()
 
1110
        {
 
1111
            if (entry == null)
 
1112
                throw new ArgumentNullException("Entry was null");
 
1113
 
 
1114
            if (entry.AtomEntry == null)
 
1115
                throw new ArgumentNullException("Entry.AtomEntry was null");
 
1116
 
 
1117
            entry.AtomEntry.Delete();
 
1118
        }
 
1119
 
 
1120
        /// <summary>
 
1121
        /// takes the given Entry and inserts its into the server
 
1122
        /// </summary>
 
1123
        /// <returns>the reflected entry from the server if any given</returns>
 
1124
        public Y Insert<Y>(Uri address, Y entry) where Y : Entry, new()
 
1125
        {
 
1126
            if (entry == null)
 
1127
                throw new ArgumentNullException("Entry was null");
 
1128
 
 
1129
            if (entry.AtomEntry == null)
 
1130
                throw new ArgumentNullException("Entry.AtomEntry was null");
 
1131
 
 
1132
            if (address == null)
 
1133
                throw new ArgumentNullException("Entry was null");
 
1134
          
 
1135
            Y r = null;
 
1136
            AtomEntry ae = this.Service.Insert(address, entry.AtomEntry);
 
1137
            if (ae != null)
 
1138
            {
 
1139
                r = new Y();
 
1140
                r.AtomEntry = ae;
 
1141
            }
 
1142
            return r;
 
1143
        }
 
1144
 
 
1145
        
 
1146
 
 
1147
        /// <summary>
 
1148
        /// takes the given Entry and inserts its into the server
 
1149
        /// </summary>
 
1150
        /// <returns>the reflected entry from the server if any given</returns>
 
1151
        public Y Insert<Y>(Feed<Y> feed, Y entry) where Y : Entry, new()
 
1152
        {
 
1153
            if (entry == null)
 
1154
                throw new ArgumentNullException("Entry was null");
 
1155
 
 
1156
            if (entry.AtomEntry == null)
 
1157
                throw new ArgumentNullException("Entry.AtomEntry was null");
 
1158
 
 
1159
            if (feed == null)
 
1160
                throw new ArgumentNullException("Feed was null");
 
1161
 
 
1162
            Y r = null;
 
1163
            AtomEntry ae = this.Service.Insert(feed.AtomFeed, entry.AtomEntry);
 
1164
            if (ae != null)
 
1165
            {
 
1166
                r = new Y();
 
1167
                r.AtomEntry = ae;
 
1168
            }
 
1169
            return r;
 
1170
        }
 
1171
 
 
1172
        /// <summary>
 
1173
        /// the Settings property returns the RequestSettings object that was used to construct this FeedRequest. 
 
1174
        /// It can be used to alter properties like AutoPaging etc, inbetween Feed creations. 
 
1175
        /// </summary>
 
1176
        ///  <example>
 
1177
        ///         The following code illustrates a possible use of   
 
1178
        ///          the <c>Settings</c> property:  
 
1179
        ///          <code>   
 
1180
        ///         YouTubeRequestSettings settings = new YouTubeRequestSettings("NETUnittests", this.ytClient, this.ytDevKey, this.ytUser, this.ytPwd);
 
1181
        ///         YouTubeRequest f = new YouTubeRequest(settings);
 
1182
        ///         Feed&lt;Video&gt; feed = f.GetStandardFeed(YouTubeQuery.MostPopular);
 
1183
        ///         foreach (Video v in feed.Entries)
 
1184
        ///         {
 
1185
        ///             f.Settings.PageSize = 50;
 
1186
        ///             f.Settings.AutoPaging = true;
 
1187
        ///             Feed&lt;Comment&gt; list = f.GetComments(v);
 
1188
        ///             foreach (Comment c in list.Entries)
 
1189
        ///              {
 
1190
        ///                 Assert.IsTrue(v.AtomEntry != null);
 
1191
        ///                  Assert.IsTrue(v.Title != null);
 
1192
        ///             }
 
1193
        ///           }
 
1194
        ///  </code>
 
1195
        ///  </example>
 
1196
        /// <returns></returns>
 
1197
        public  RequestSettings Settings
 
1198
        {
 
1199
            get
 
1200
            {
 
1201
                return this.settings;
 
1202
            }
 
1203
        }
 
1204
    }
 
1205
}