// Modified by Yen-Ju Chen <yjchenx@hotmail.com>
/*
**  Channel.m
**
**  Copyright (c) 2002
**
**  Author: Ludovic Marcotte <ludovic@Sophos.ca>
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation; either version 2 of the License, or
**  (at your option) any later version.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "Channel.h"

#include "Plop.h"
#include "PlopletView.h"
#include <AppKit/AppKit.h>

// XML Headers needed under GNUstep
#include <Foundation/GSXML.h>
#include <libxml/tree.h>

@implementation Channel

- (id) initWithContentsOfFile: (NSString *) file
{
  NSString *string;
  NSData *data;

  self = [self init];

  string = [NSString stringWithContentsOfFile: file];
  data = [string dataUsingEncoding: NSISOLatin1StringEncoding];
  [self processData: data];

  return self;
}

- (id) initWithURL: (NSURL *) aURL
{
  self = [self init];

  [aURL loadResourceDataNotifyingClient: self usingCache: YES];
//  [self processData: [aURL resourceDataUsingCache: NO]];
  return self;
}

- (id) init
{
  self = [super init];

  allElements = [[NSMutableArray alloc] init];
  totalBytes = 0;

  return self;
}

- (void) dealloc
{
  RELEASE(allElements);
  RELEASE(plop);

  [super dealloc];
}

// access / mutation methods
- (void) addElement: (Element *) theElement
{
  [allElements addObject: theElement];
}

- (void) removeElement: (Element *) theElement
{
  [allElements removeObject: theElement];
}

- (void) removeAllElements
{
  [allElements removeAllObjects];
}

- (int) count
{
  return [allElements count];
}

- (int) itemCount
{
  int i, count;
  
  count = 0;

  for (i = 0; i < [allElements count]; i++)
    {
      Element *aElement;

      aElement = [allElements objectAtIndex: i];

      if ( [aElement type] == ITEM )
	{
	  count++;
	}
    }
  return count;
}

- (Element *) elementAtIndex: (int) theIndex
{
  return [allElements objectAtIndex: theIndex];
}

- (Plop *) plop
{
  return plop;
}

- (void) setPlop: (Plop *) thePlop
{
  ASSIGN(plop, thePlop);
}

- (PlopletView *) plopletView
{
  return plopletView;
}

// No need to RETAIN here
- (void) setPlopletView: (PlopletView *) theView
{
  plopletView = theView;
}

- (void) URL: (NSURL *) sender 
         resourceDataDidBecomeAvailable: (NSData *) newBytes
{
  totalBytes += [newBytes length];
  // We finally update our "view"
  if ( [self plopletView] )
    {
      [[self plopletView] updateTextView: [NSString stringWithFormat: @"Loading %d bytes ...", totalBytes]];
    }
}

- (void) URL: (NSURL *) sender
         resourceDidFailLoadingWithReason: (NSString *) reason
{
  NSLog(@"failed loading URL, reason: %@:", reason);
}

- (void) URLResourceDidFinishLoading: (NSURL *) sender 
{
  [self processData: [sender resourceDataUsingCache: YES]];
}

- (void) URLResourceDidCancelLoading: (NSURL*) sender
{
  // We do nothing here
}

- (void) processData: (NSData *) aData;
{
  // GNUstep XML Parsing Code
  GSXMLParser *aParser;

  if ( !aData )
    {
      NSLog(@"Unable to get the data from the content source. Ignoring Plop.");
      return;
    }

  [self removeAllElements];
  aParser = [GSXMLParser parserWithData: aData];

  if ( [aParser parse] )
    {
      GSXMLDocument *aDocument;
      GSXMLNode *aRoot, *aNode;
      
// FIXME: Not sure about this
//      aDocument = [aParser doc];
      aDocument = [aParser document];
      aRoot = [aDocument root];
            
      aNode = [aRoot firstChild];
      
      //
      // We loop inside our channel/image/item nodes
      //
      while (aNode != nil)
	{ 
	  if ( [aNode type] == XML_ELEMENT_NODE )
	    {
	      if ( [[aNode name] caseInsensitiveCompare: @"CHANNEL"] == NSOrderedSame )
		{
		  [self _parseNodeInformationUsingElement: self
			node: aNode];
		}
	      else
		{
		  Element *aElement;
		  
		  aElement = [[Element alloc] init];
		  
		  [self _parseNodeInformationUsingElement: aElement
			node: aNode];
		  
		  [self addElement: aElement];
		  RELEASE(aElement);
		}
	    }
	  
	  // We get the next node
	  aNode = [aNode next];
	}

      // We finally update our "view"
      if ( [self plopletView] )
	{
	  [[self plopletView] updateTextView: nil];
	}
    }
  else
    {
      NSLog(@"Error while decoding the RDF content.");
    }
}

@end

// Private methods

@implementation Channel (Private)


- (void) _updateElement: (Element *) theElement
		   name: (NSString *) theName
		content: (NSString *) theContent
{
  if ( [theName caseInsensitiveCompare: @"TITLE"] == NSOrderedSame )
    {
      [theElement setTitle: theContent];
    }
  else if ( [theName caseInsensitiveCompare: @"LINK"] == NSOrderedSame )
    {
      [theElement setLink: [NSURL URLWithString: theContent] ];
    }
  else if ( [theName caseInsensitiveCompare: @"DESCRIPTION"] == NSOrderedSame )
    {
      [theElement setDescription: theContent];
    }
  else if ( [theName caseInsensitiveCompare: @"URL"] == NSOrderedSame )
    {
      [theElement setURL: [NSURL URLWithString: theContent] ];
    }
}

- (void) _parseNodeInformationUsingElement: (Element *) theElement
				      node: (id) theNode
{
  NSString *aNodeName;
  GSXMLNode *aChild;
  
  aNodeName = [(GSXMLNode *)theNode name];

  // We decode the right type
  if ( [aNodeName caseInsensitiveCompare: @"CHANNEL"] == NSOrderedSame )
    {
      [theElement setType: CHANNEL];
    }
  else if ( [aNodeName caseInsensitiveCompare: @"IMAGE"] == NSOrderedSame )
    {
      [theElement setType: IMAGE];
    }
  else if ( [aNodeName caseInsensitiveCompare: @"ITEM"] == NSOrderedSame )
    {
      [theElement setType: ITEM];
    }
  else if ( [aNodeName caseInsensitiveCompare: @"TEXTINPUT"] == NSOrderedSame )
    {
      [theElement setType: TEXTINPUT];
    }
  else
    {
      [theElement setType: UNKNOWN];
    }

  // We loop inside our channel/image/item node attributes
  if ( (aChild = [theNode firstChild]) )
    {
      while ( aChild )
	{
	  NSString *aName, *aContent;
	  GSXMLNode *aNode;
	  
	  //
	  // Ok, this is kinda weird. Some klips are defined like that:
	  //
	  // <channel>... </channel>
	  // <item>...</item>
	  // 
	  // and some like:
	  //
	  // <channel>
	  //   <item>...</item>
	  // </channel>
	  //
	  if ( [[aChild name] caseInsensitiveCompare: @"ITEM"] == NSOrderedSame ||
	       [[aChild name] caseInsensitiveCompare: @"IMAGE"] == NSOrderedSame ||
	       [[aChild name] caseInsensitiveCompare: @"TEXTINPUT"] == NSOrderedSame ) 
	    {
	      Element *aElement;
	      
	      aElement = [[Element alloc] init];
	      
	      [self _parseNodeInformationUsingElement: aElement
		    node: aChild];
	      
	      [self addElement: aElement];
	      RELEASE(aElement);
	      
	      aChild = [aChild next];
	      continue;
	    }

          aNode = [aChild firstChild];

	  while ( aNode )
	    {
	      if ( [aNode type] == XML_TEXT_NODE )
		{
		  if ( [[[aNode content] stringByTrimmingSpaces] length] > 0 )
		    {
		      break;
		    }
		}
	      
	      aNode = [aNode next];
	    }
	  
	  if ( !aNode )
	    {
	      aChild = [aChild next];
	      continue;
	    }
	  

	  aName = [aChild name];
	  aContent = [[aNode content] stringByTrimmingSpaces];
	  
	  if ( aName && aContent )
	    {
	      [self _updateElement: theElement
		    name: aName
		    content: aContent];
	    }
	  
	  aChild = [aChild next];
	}
    }
  else
    {
      NSLog(@"No children");
    }
}

@end

