/*
 *	Collecor playlist V0.0
 */
#include <InterfaceKit.h>
#include "PlayList.h"

static const char 		*PLAYLIST_NAME =	"Collector";
static const uint32 	WIN_SHOWW =		'show';
static const uint32 	WIN_HIDEW =		'hidw';
static const uint32 	LST_BASEDIR =		'base';
static const uint32 	LST_SETDIR =		'setd';
static const uint32 	INFO_TITLE =		'ittl';
static const uint32 	INFO_AUTHOR =		'iaut';
static const uint32 	INFO_STYLE =		'isty';
static const uint32 	INFO_COPYRIGHT =	'icpy';
static const uint32 	INFO_LENGTH =		'ilen';
static const uint32 	INFO_FORMAT =		'ifmt';
static const uint32 	LST_RENAME =		'pren';
static const uint32 	LST_DELETE =		'pdel';
static const uint32 	LST_NAME =		'pnam';
static const uint32 	LST_TYPE =		'ptyp';
static const uint32 	LST_SIZE =		'psiz';
static const uint32 	LST_REVERSE =	'prev';
static const float 	ITEM_HEIGHT =		18.0;

// Prototype classes
class DListItem;
class PListItem;
class DListView;
class PListView;
class Database;
class InfoView;
class MikListWindow;

enum 
{
	SORT_NAME,
	SORT_TYPE,
	SORT_SIZE,
	SORT_REVERSE=0x80,
};

// small icon for unknown files, 16x16,8Bit
static const unsigned char smallicons[]=
{
	
	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0x00,0xfa,0xfa,0xfa,
	0xfa,0xfa,0xfa,0x00,0x00,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0xfa,0xfa,0xfa,0xfa,
	0xfa,0xfa,0xfa,0xfa,0x00,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0xf8,0xf8,0x00,0x00,
	0x00,0x00,0xf8,0xf8,0x00,0xff,0xff,0xff,
	0xff,0xff,0xff,0x00,0xf8,0xf8,0x00,0xac,
	0xac,0x00,0xf8,0xf8,0x00,0xff,0xff,0xff,
	0xff,0xff,0xd3,0x00,0x5d,0x5d,0x00,0xac,
	0x00,0x00,0x5d,0x5d,0x00,0xd3,0xff,0xff,
	0xff,0xd3,0xac,0x00,0x5d,0x5d,0x00,0x00,
	0x00,0x5d,0x5d,0x5d,0x00,0xac,0xf3,0xff,
	0xff,0xd3,0xac,0x00,0x00,0x00,0x00,0x00,
	0x5d,0x5d,0x5d,0x00,0x00,0xac,0xd3,0xff,
	0xff,0xd3,0xac,0xac,0xac,0xac,0x00,0x7d,
	0x7d,0x7d,0x00,0x00,0xac,0xac,0xd3,0xff,
	0xff,0xd3,0xac,0xac,0xac,0xac,0x00,0x7d,
	0x7c,0x00,0x00,0xac,0xac,0xac,0xf3,0xff,
	0xff,0xff,0xd3,0xac,0xac,0xac,0x00,0x7c,
	0x7c,0x00,0xac,0xac,0xac,0xf3,0x15,0xff,
	0xff,0xff,0xff,0xd3,0xac,0xac,0x00,0x7c,
	0x7c,0x00,0xac,0xac,0xf3,0x15,0xff,0xff,
	0xff,0xff,0xff,0xff,0xd3,0xac,0x00,0x00,
	0x00,0x00,0xac,0xd3,0x15,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xd3,0x00,0x7c,
	0x7c,0x00,0xd3,0x15,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x7c,
	0x7c,0x00,0x15,0xff,0xff,0xff,0xff,0xff,
	0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
	0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
};

// Instance of the Zoonic class 
struct instance_struct
{
	BMessage 		*prefs;
	Object 		*dual_object;
	MikListWindow	*list;
	DListView		*dlist;
	PListView		*plist;
	InfoView		*iview;
	sem_id		close_sem;
};

class StringView : public BView
{
	BTextControl	*fname;
	BButton		*bok;
	BButton		*bcancel;

	public:
				StringView():BView(BRect(0,0,323,50),"",NULL,B_WILL_DRAW)
				{						
				};	
				
	void			AttachedToWindow()
				{
					SetViewColor(200,200,200);						

					AddChild(fname = new BTextControl(BRect(3,3,319,21),"Name","Name","",new BMessage('SHIT')));
					AddChild(bok = new BButton(BRect(200,24,250,42),"OK","OK",new BMessage('OKIT')));
					AddChild(bcancel = new BButton(BRect(255,24,319,42),"Cancel","Cancel",new BMessage('CANC')));
				
					fname->SetDivider(0);
					fname->MakeFocus();	
				};
				
	void			SetText(char *def)
				{
					fname->SetText(def);
				};

	const char	*Text()
				{
					return fname->Text();
				};
				
		void		OK()	
				{
					bok->Invoke(NULL);
				};		
};

class StringRequester : public BWindow
{

	BHandler		*handler;
	StringView	*view;

	public:
				StringRequester():BWindow(BRect(0,0,323,50),"Rename...",B_TITLED_WINDOW,B_NOT_CLOSABLE | B_NOT_RESIZABLE)
				{
					view = new StringView();
					AddChild(view);
					
					BScreen *screen = new BScreen();
					MoveTo((screen->Frame().Width()-324)/2,(screen->Frame().Height()-51)/2);
					delete screen;
					
					Run();
				};
				
	void			Prepare(BHandler *h, char *def)
				{
					Lock();
					handler=h;
					view->SetText(def);
					Unlock();
				}

	void			MessageReceived(BMessage *msg)
				{
					switch(msg->what)
					{
						case		'SHIT':
						case		'OKIT':
								{
									BMessage msg = BMessage('RENA');
									msg.AddString("Name",view->Text());
									handler->MessageReceived(&msg);
									Hide();
								}
								break;
						case		'CANC':
								{
									Hide();
								}
								break;
					}
				};

	bool			QuitRequested(void)
				{
					return true;
				}
};

StringRequester *requester;

// Filter for directory selector
class MyFilter : public BRefFilter 
{
	public:

	virtual	bool	Filter(const entry_ref *ref, BNode *node, struct stat *s, const char *mimetype)
				{
					BEntry entry = BEntry(ref);
					
					if(entry.IsDirectory())
					{
						return TRUE;
					}
					else
					{
						return FALSE;
					}
				};
};

// Fileitem
class PListItem : public BListItem
{
	private:

	char 		*path;
	off_t 		size;
	BListView		*plst;
	BBitmap		*bmp;
	bool			dragged;
	bool			existant;
	char 		type[256];					
	bool			islink;


	public:

			PListItem(BListView *pl):BListItem()
			{
				plst=pl;
				path=0;
				size=0;
				bmp=0;
				existant=true;
				dragged=false;
				islink=false;
			};

			~PListItem()
			{
				if(path) free(path);
				if(bmp) delete bmp;
			};

	char		*extract_name(char *path)
			{
				int32 c=strlen(path);
				int32 pos=0;
				
				for(int32 i=0;i<c;i++)
					if(path[i]=='/') pos=i+1;
			
				return &path[pos];
			};
			
	PListView	*Container()
			{
				return (PListView *)plst;
			};

	void		SetDragged(bool d)
			{
				dragged=d;
			};

	void		SetPath(const char *p)
			{					
				BNode addnode = BNode();
				BEntry addentry = BEntry();
				BMimeType *addmime = new BMimeType();

				if(path) free(path);
				if(bmp) delete bmp;

				if(p)path=strdup(p);
				else path=strdup(" ");

				addentry.SetTo(path);
				if(addentry.GetSize(&size)!=B_NO_ERROR)
				{
					existant=false;
				}
				
				if(addentry.IsSymLink())
				{
					islink=true;
				}
		
				addnode.SetTo(path);
				BNodeInfo *nodeinfo = new BNodeInfo(&addnode);

				bmp = new BBitmap(BRect(0,0,15,15),B_COLOR_8_BIT);

				if(nodeinfo->GetType(type)!=B_NO_ERROR)
				{
					bmp->SetBits(smallicons,16*16,0,B_COLOR_8_BIT);
				}
				else
				{

					addmime->SetType((const char *)type);						
					if(addmime->IsValid())
					{
						if(addmime->GetIcon(bmp,B_MINI_ICON)!=B_NO_ERROR)
						{
							bmp->SetBits(smallicons,16*16,0,B_COLOR_8_BIT);
						}
					}
					else
					{
						bmp->SetBits(smallicons,16*16,0,B_COLOR_8_BIT);
					}
				}
				delete nodeinfo;
				delete addmime;
			};
				
	char		*Path()
			{
				return path;
			};

	char		*Type()
			{
				return type;
			};
				
	int32	Size()
			{
				return (int32)size;
			};

	float	ItemHeight()
			{
				return ITEM_HEIGHT;
			};
		
	void		Update(BView *owner, const BFont *font)
			{
				SetWidth(1024);
				SetHeight(ITEM_HEIGHT);
				owner->SetFont(font);
				owner->SetFontSize(10.0);
			};

	void		DrawItem(BView *view, BRect frame, bool complete = false)
			{				
				char 		tmp[64];
				int32		index=plst->IndexOf(this);

				font_height fh;
				be_plain_font->GetHeight(&fh);						
				view->SetDrawingMode(B_OP_COPY);
				view->SetFontSize(10.0);
				
				if(IsSelected())
				{
					if(dragged)
						view->SetHighColor(0,0,128);
					else
						view->SetHighColor(128,0,0);
				}
				else
				{
					if(index&1)
						view->SetHighColor(222,222,222);
					else
						view->SetHighColor(200,200,200);
				}
				
				view->FillRect(frame);
				
				if(IsSelected())
				{
					view->SetHighColor(255,255,255);
					if(dragged)
						view->SetLowColor(0,0,128);
					else
						view->SetLowColor(128,0,0);
				}
				else
				{
					view->SetHighColor(0,0,0);
					if(index&1)
						view->SetLowColor(222,222,222);
					else
						view->SetLowColor(200,200,200);
				}
				
				view->DrawString(extract_name(path),BPoint(26,frame.top+fh.ascent+3));
				view->SetDrawingMode(B_OP_OVER);
				view->DrawBitmap(bmp,frame.LeftTop()+BPoint(4,2));
				view->SetDrawingMode(B_OP_COPY);				
			};
};

// Directoryitem
class DListItem : public BListItem
{
	private:

	char 		*path;
	BListView		*plst;
	float 		maxw;

	public:
			DListItem(BListView *pl):BListItem()
			{
				plst=pl;
				path=0;
			};

			~DListItem()
			{
				if(path) free(path);
			};

	char 	*extract_name(char *path)
			{
				int32 c=strlen(path);
				int32 pos=0;
				
				for(int32 i=0;i<c;i++)
					if(path[i]=='/') pos=i+1;
			
				return &path[pos];
			};

	DListView	*Container()
			{
				return (DListView *)plst;
			};
				
	void		SetPath(const char *p)
			{
				path=strdup(p);
			};
			
	char 	*Path()
			{
				return path;
			};
		
	void		Update(BView *owner, const BFont *font)
			{
				SetWidth(1024);
				SetHeight(ITEM_HEIGHT);
				owner->SetFont(font);
				owner->SetFontSize(10.0);
				maxw=owner->StringWidth("888,888,888");
			};
				
	float	ItemHeight()
			{
				return ITEM_HEIGHT;
			};
		
	void		DrawItem(BView *view, BRect frame, bool complete = false)
			{				
				int32		index=plst->IndexOf(this);

				font_height fh;
				be_plain_font->GetHeight(&fh);						
				view->SetDrawingMode(B_OP_COPY);
				view->SetFontSize(10.0);
				
				if(IsSelected())
				{
					view->SetHighColor(128,0,0);
				}
				else
				{
					if(index&1)
						view->SetHighColor(222,222,222);
					else
						view->SetHighColor(200,200,200);
				}
				
				view->FillRect(frame);
				
				if(IsSelected())
				{
					view->SetHighColor(255,255,255);
					view->SetLowColor(128,0,0);
				}
				else
				{
					view->SetHighColor(0,0,0);
					if(index&1)
						view->SetLowColor(222,222,222);
					else
						view->SetLowColor(200,200,200);
				}

				view->DrawString(extract_name(path),BPoint(6,frame.top+fh.ascent+3));

			};
};

// Description view, right view
class InfoView : public  BView
{
	private:
	
	instance_struct	*inst;
	
	BTextControl		*title;
	BTextControl		*author;
	BTextControl		*style;
	BTextControl		*copyright;
	BTextControl		*length;
	BTextControl		*format;
	BTextControl		*date;
	BTextControl		*origin;
	BTextView			*comment;
	
	BPoint 			minsize;
	char				actfile[1024];
	char 			*tmp;
	
	public:
					InfoView(instance_struct *i,BRect frame):BView(frame,"InfoView",NULL,B_WILL_DRAW)
					{
						inst=i;	
						SetFlags(Flags() | B_FRAME_EVENTS);
						tmp=(char *)malloc(65536);
					};
					
					~InfoView()
					{
						Clear();
						free(tmp);
					}
					
		void			AttachedToWindow()
					{
						int32 index=0;
						const float textview_framewidth=2;
						const float min_button_width=16;
						const float lr_space=4;
						const float tb_space=8;
						float abstand = be_plain_font->Size()+10; 
						float hoehe = be_plain_font->Size()+4;

						float divider = max_c(be_plain_font->StringWidth("Title"),
									  max_c(be_plain_font->StringWidth("Author"),
									  max_c(be_plain_font->StringWidth("Style"),
									  max_c(be_plain_font->StringWidth("Copyright"),
									  max_c(be_plain_font->StringWidth("Length"),
									  max_c(be_plain_font->StringWidth("Origin"),
									  be_plain_font->StringWidth("Format")
									  ))))))+lr_space;

						BRect frame=Bounds();						

						title  		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Title","Title","",new BMessage(INFO_TITLE));
						index++;
						author 		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Author","Author","",new BMessage(INFO_AUTHOR));
						index++;
						copyright  	= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Copyright","Copyright","",new BMessage(INFO_COPYRIGHT));
						index++;
						origin  		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Origin","Origin","",new BMessage(INFO_COPYRIGHT));
						index++;
						style  		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Style","Style","",new BMessage(INFO_STYLE));
						index++;
						length  		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Length","Length","",new BMessage(INFO_LENGTH));
						index++;
						format  		= new BTextControl(BRect(frame.LeftTop()+BPoint(lr_space,tb_space+abstand*index),frame.RightTop()+BPoint(-lr_space,tb_space+abstand*(index)+hoehe)),"Format","Format","",new BMessage(INFO_FORMAT));
						index++;
						comment		= new BTextView(BRect(frame.LeftTop()+BPoint(lr_space+textview_framewidth,tb_space+textview_framewidth+abstand*(index)),frame.RightBottom()+BPoint(-lr_space-textview_framewidth,-tb_space-textview_framewidth)),"Comment",BRect(0,0,0,0), B_FOLLOW_ALL, B_WILL_DRAW);
						index++;

						title->SetTarget(this);
						author->SetTarget(this);
						copyright->SetTarget(this);
						origin->SetTarget(this);
						style->SetTarget(this);
						length->SetTarget(this);
						format->SetTarget(this);
						
						title->SetDivider(divider);
						author->SetDivider(divider);
						style->SetDivider(divider);
						copyright->SetDivider(divider);
						origin->SetDivider(divider);
						length->SetDivider(divider);
						format->SetDivider(divider);
						comment->SetTextRect(BRect(BPoint(1,1),comment->Bounds().RightBottom()-BPoint(1,1)));
						comment->SetMaxBytes(65535);
						
						AddChild(title);
						AddChild(author);
						AddChild(copyright);
						AddChild(origin);
						AddChild(style);
						AddChild(length);
						AddChild(format);
						AddChild(comment);

						title->SetViewColor(200,200,200);
						author->SetViewColor(200,200,200);
						style->SetViewColor(200,200,200);
						copyright->SetViewColor(200,200,200);
						origin->SetViewColor(200,200,200);
						length->SetViewColor(200,200,200);
						format->SetViewColor(200,200,200);

						title->SetLowColor(200,200,200);
						author->SetLowColor(200,200,200);
						style->SetLowColor(200,200,200);
						copyright->SetLowColor(200,200,200);
						origin->SetLowColor(200,200,200);
						length->SetLowColor(200,200,200);
						format->SetLowColor(200,200,200);
						
						minsize.x=lr_space*3+divider+min_button_width;
						minsize.y=abstand*index+tb_space*2;
					}

 		BPoint		MinSize(void)
					{
						return minsize;
					}
					
		void			MessageReceived(BMessage *msg)
					{
						UpdateSave();
					}
										
		void			UpdateSave(void)
					{
						BNode node = BNode(actfile);
						if(node.IsFile())
						{
							node.RemoveAttr("dp_title");
							node.WriteAttr("dp_title",B_STRING_TYPE,0,title->Text(),strlen(title->Text())+1);
							node.RemoveAttr("dp_author");
							node.WriteAttr("dp_author",B_STRING_TYPE,0,author->Text(),strlen(author->Text())+1);
							node.RemoveAttr("dp_style");
							node.WriteAttr("dp_style",B_STRING_TYPE,0,style->Text(),strlen(style->Text())+1);
							node.RemoveAttr("dp_copyright");
							node.WriteAttr("dp_copyright",B_STRING_TYPE,0,copyright->Text(),strlen(copyright->Text())+1);
							node.RemoveAttr("dp_origin");
							node.WriteAttr("dp_origin",B_STRING_TYPE,0,origin->Text(),strlen(origin->Text())+1);
							node.RemoveAttr("dp_length");
							node.WriteAttr("dp_length",B_STRING_TYPE,0,length->Text(),strlen(length->Text())+1);
							node.RemoveAttr("dp_format");
							node.WriteAttr("dp_format",B_STRING_TYPE,0,format->Text(),strlen(format->Text())+1);
							node.RemoveAttr("dp_comment");
							node.WriteAttr("dp_comment",B_STRING_TYPE,0,comment->Text(),min_c(65536,comment->TextLength()+1));
						}
					}

		void			Clear(void)
					{
						UpdateSave();
						strcpy(actfile,"");
						title->SetText("");
						author->SetText("");
						style->SetText("");
						copyright->SetText("");
						origin->SetText("");
						length->SetText("");
						format->SetText("");
						comment->SetText("");							
					};
		
		void			UpdateFile(const char *file)
					{		
						if(strcmp(file,actfile)!=0)
						{				
							Clear();	
							strcpy(actfile,file);
							BNode node = BNode(actfile);						
							if(node.IsFile())
							{
								attr_info info;
							
								if(node.GetAttrInfo("dp_title",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_title",B_STRING_TYPE,0,tmp,1024);
									title->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_author",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_author",B_STRING_TYPE,0,tmp,1024);
									author->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_style",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_style",B_STRING_TYPE,0,tmp,1024);
									style->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_copyright",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_copyright",B_STRING_TYPE,0,tmp,1024);
									copyright->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_origin",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_origin",B_STRING_TYPE,0,tmp,1024);
									origin->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_length",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_length",B_STRING_TYPE,0,tmp,1024);
									length->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_format",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_format",B_STRING_TYPE,0,tmp,1024);
									format->SetText(tmp);
								}
								if(node.GetAttrInfo("dp_comment",&info)==B_NO_ERROR)
								{
									node.ReadAttr("dp_comment",B_STRING_TYPE,0,tmp,65536);
									comment->SetText(tmp);
								}
							}
						}
					};
		
		void			FrameResized(float x, float y)
					{
						BRect frame = Bounds();
						
						float hoehe = be_plain_font->Size()+8;
						float breite = frame.Width()-8;
						
						title->ResizeTo(breite,hoehe);
						author->ResizeTo(breite,hoehe);
						style->ResizeTo(breite,hoehe);
						copyright->ResizeTo(breite,hoehe);
						origin->ResizeTo(breite,hoehe);
						length->ResizeTo(breite,hoehe);
						format->ResizeTo(breite,hoehe);
						comment->SetTextRect(BRect(BPoint(0,0),comment->Bounds().RightBottom()));
					};
				
		void			Draw(BRect frame)
					{
						SetHighColor(200,200,200);
						FillRect(frame);

						frame = comment->Frame();
						
						SetHighColor(150,150,150);
						StrokeRect(BRect(frame.LeftTop()-BPoint(1,1),frame.RightBottom()+BPoint(1,1)));
						SetHighColor(255,255,255);
						StrokeLine(frame.RightTop()+BPoint(2,-2),frame.RightBottom()+BPoint(2,2));
						StrokeLine(frame.LeftBottom()+BPoint(-2,2),frame.RightBottom()+BPoint(2,2));
						SetHighColor(180,180,180);
						StrokeLine(frame.LeftTop()+BPoint(-2,-2),frame.RightTop()+BPoint(2,-2));
						StrokeLine(frame.LeftTop()+BPoint(-2,-2),frame.LeftBottom()+BPoint(-2,2));
					};
};

// Fileview, middle view
class PListView : public BListView
{
	private:
	
	BPopUpMenu 			*pop;
	instance_struct		*inst;
	BScrollBar 			*bar;
	char					pathsave[1024];
	bigtime_t				db;
	int32				sorttype;
	
	BMenuItem				*sname;
	BMenuItem				*stype;
	BMenuItem				*ssize;
	BMenuItem				*sreve;

	public:
						PListView(instance_struct *i, BRect frame):BListView(frame,"PListView",B_SINGLE_SELECTION_LIST,B_FOLLOW_NONE)
						{
							inst=i;
							
							db=0;
							
							sorttype=inst->prefs->FindInt32("CollectorFileSort");							
							SetFlags( Flags() | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE);
						};

	char					*extract_name(char *path)
						{
							int32 c=strlen(path);
							int32 pos=0;
							
							for(int32 i=0;i<c;i++)
								if(path[i]=='/') pos=i+1;
						
							return &path[pos];
						};

			int32		SortType(void)
						{
							return sorttype;
						};

	static	int			Sorter(const void *v1, const void *v2)
	 					{
	 						if(v1==0 || v2==0) return 0;
	 						
	 						PListItem *i1=*((PListItem **)v1);
	 						PListItem *i2=*((PListItem **)v2);
	 						
	 						char cmp1[1024];
	 						char cmp2[1024];
	 					
	 						switch(i1->Container()->SortType() & 0x0f)
	 						{
	 							case		SORT_NAME:
	 									{
	 										strcpy(cmp1,i1->extract_name(i1->Path()));
	 										strcpy(cmp2,i2->extract_name(i2->Path()));
	 									}
	 									break;
	 							case		SORT_TYPE:
	 									{
		 									{
			 									BNode node = BNode();
			 									node.SetTo(i1->Path());
												BNodeInfo *nodeinfo = new BNodeInfo(&node);
			 									nodeinfo->GetType(cmp1);
			 									delete nodeinfo;
			 									strcat(cmp1,i1->extract_name(i1->Path()));
											}
											{
			 									BNode node = BNode();
			 									node.SetTo(i2->Path());
												BNodeInfo *nodeinfo = new BNodeInfo(&node);
			 									nodeinfo->GetType(cmp2);
			 									delete nodeinfo;
			 									strcat(cmp2,i2->extract_name(i2->Path()));
											}
										}											 									
	 									break;
	 							case		SORT_SIZE:
	 									{
		 									BEntry e1=BEntry(i1->Path());
		 									BEntry e2=BEntry(i2->Path());	
											off_t s1,s2;
											e1.GetSize(&s1);
											e2.GetSize(&s2);
											
											if(i1->Container()->SortType() & SORT_REVERSE)
					 						{
					 							return s1-s2;
					 						}
					 						else
					 						{
					 							return s2-s1;
					 						}
										}	 							
	 									break;
	 						}	 						
	 						if(i1->Container()->SortType() & SORT_REVERSE)
	 						{
	 							return strcasecmp(cmp2,cmp1);
	 						}
	 						else
	 						{
	 							return strcasecmp(cmp1,cmp2);
	 						}
	 					};

			void			MouseDown(BPoint where)
						{
							BPoint moved;
							uint32 buttons,index;
							int64 clickspeed;
						
							ConstrainClippingRegion(NULL);
						
							get_click_speed(&clickspeed);
						
							GetMouse(&where,&buttons);
						
							if(buttons&B_SECONDARY_MOUSE_BUTTON)
							{
								pop->Go(ConvertToScreen(where)-BPoint(2,2),TRUE,TRUE,Frame());
								
								return;		
							}
						
							index=IndexOf(where);
							if(index!=CurrentSelection())
							{
								Select(index);
					 			db=0;
							}
							if((system_time()-db)<clickspeed)
							{	
								Invoke(NULL);
								db=0;	
							}
							else
							{
								db=system_time();
							}
						};

			void			AttachedToWindow()
						{
							BPopUpMenu *menu = new BPopUpMenu("PListDirectory",FALSE,FALSE);
							BMenuItem  *item;
						
							item = new BMenuItem("Rename…", new BMessage(LST_RENAME),NULL);
							menu->AddItem(item);
//							item = new BMenuItem("Delete", new BMessage(LST_DELETE),NULL);
//							menu->AddItem(item);
							menu->AddItem(new BSeparatorItem());
							sname = item = new BMenuItem("Sort by name", new BMessage(LST_NAME),NULL);
							menu->AddItem(item);
							stype = item = new BMenuItem("Sort by type", new BMessage(LST_TYPE),NULL);
							menu->AddItem(item);
							ssize = item = new BMenuItem("Sort by size", new BMessage(LST_SIZE),NULL);
							menu->AddItem(item);
							sreve = item = new BMenuItem("Reverse Sorting", new BMessage(LST_REVERSE),NULL);
							menu->AddItem(item);
							
							menu->SetTargetForItems(this);
							
							switch(sorttype&(!SORT_REVERSE))
							{
								case		SORT_NAME:
										sname->SetMarked(TRUE);
										break;
								case		SORT_TYPE:
										stype->SetMarked(TRUE);
										break;
								case		SORT_SIZE:
										ssize->SetMarked(TRUE);
										break;
							}
							if(sorttype&SORT_REVERSE)
							{
								sreve->SetMarked(TRUE);
							}

							pop=menu;

							bar	= new BScrollBar(BRect(Frame().RightTop()+BPoint(1,0),Frame().RightBottom()+BPoint(B_V_SCROLL_BAR_WIDTH,0)),"",this,0,0,B_VERTICAL);
							Window()->AddChild(bar);
							bar->SetResizingMode(B_FOLLOW_NONE);
							bar->SetFlags( bar->Flags() | B_FULL_UPDATE_ON_RESIZE );
							SetLowColor(200,200,200);
							SetViewColor(200,200,200);
							update_self();
							BListView::AttachedToWindow();
							SetFont(be_plain_font);
							SetFontSize(9);
							MakeFocus();
						};
						
			
			status_t		Invoke(BMessage *msg)
						{
							if((CurrentSelection()>=0) && (CurrentSelection()<CountItems()))
								inst->dual_object->DoMethod(D_NEW_FILE,((PListItem *)ItemAt(CurrentSelection()))->Path(),CurrentSelection());
							return B_NO_ERROR;
						};

			void			MessageReceived(BMessage *msg)
						{
							switch(msg->what)
							{
								case		'NDMN':
										{
											int32 opcode;
											if(msg->FindInt32("opcode",&opcode)==B_NO_ERROR)
											{
												switch(opcode)
												{
													case		B_ENTRY_CREATED:
													case		B_ENTRY_REMOVED:
													case		B_ENTRY_MOVED:
													case		B_STAT_CHANGED:
													case		B_ATTR_CHANGED:
															Update();
															break;
												}
											}
										}
										break;
								case		'RENA':
										{
											const char *tmp;
											msg->FindString("Name",&tmp);
											
											if((inst->plist->CurrentSelection()>=0) && (inst->plist->CurrentSelection()<inst->plist->CountItems()))
											{	
												PListItem *i=(PListItem *)ItemAt(inst->plist->CurrentSelection());
												
												BEntry entry = BEntry(i->Path());
												entry.Rename(tmp);
											}
										}
										break;										
								case		LST_RENAME:
										{
											if((CurrentSelection()>=0) && (CurrentSelection()<CountItems()))
											{	
												PListItem *i=(PListItem *)ItemAt(CurrentSelection());
												requester->Prepare(this,extract_name(i->Path()));
												requester->Show();
											}
										}
										break;
								case		LST_NAME:
										sorttype=SORT_NAME | (sorttype&0xF0);
										sname->SetMarked(TRUE);
										stype->SetMarked(FALSE);
										ssize->SetMarked(FALSE);										
										inst->prefs->ReplaceInt32("CollectorFileSort",sorttype);
										Window()->Lock();
										SortItems(&Sorter);
										Window()->Unlock();
										break;
								case		LST_TYPE:
										sorttype=SORT_TYPE | (sorttype&0xF0);
										sname->SetMarked(FALSE);
										stype->SetMarked(TRUE);
										ssize->SetMarked(FALSE);										
										inst->prefs->ReplaceInt32("CollectorFileSort",sorttype);
										Window()->Lock();
										SortItems(&Sorter);
										Window()->Unlock();
										break;
								case		LST_SIZE:
										sorttype=SORT_SIZE | (sorttype&0xF0);
										sname->SetMarked(FALSE);
										stype->SetMarked(FALSE);
										ssize->SetMarked(TRUE);										
										inst->prefs->ReplaceInt32("CollectorFileSort",sorttype);
										Window()->Lock();
										SortItems(&Sorter);
										Window()->Unlock();
										break;
								case		LST_REVERSE:
										if(sorttype&SORT_REVERSE)
										{
											sorttype&=0xF;
											sreve->SetMarked(FALSE);
										}
										else
										{	
											sorttype|=SORT_REVERSE;
											sreve->SetMarked(TRUE);
										}
										inst->prefs->ReplaceInt32("CollectorFileSort",sorttype);
										Window()->Lock();
										SortItems(&Sorter);
										Window()->Unlock();
										break;
							}
						};

			void			Update()
						{
							UpdateDirectory(pathsave);
						};

			void			UpdateDirectory(char *newpath)
						{
							PListItem *i;
							
							while(i=(PListItem *)RemoveItem((int32)0)) delete i;
						
							stop_watching(this); 
							
							strcpy(pathsave,newpath);
							
							node_ref node;
							BDirectory dir = BDirectory(newpath); 
							BEntry stat = BEntry(newpath);
							BEntry file = BEntry();
							BPath path = BPath();
							BList list = BList();

							stat.GetNodeRef(&node);
							watch_node(&node,B_WATCH_DIRECTORY|B_WATCH_NAME|B_WATCH_STAT,this);

							dir.Rewind();
							while(dir.GetNextEntry(&file)==B_NO_ERROR)
							{
								file.GetPath(&path);
								i = new PListItem(this);
								i->SetPath(path.Path());
								list.AddItem(i);
							}

							Window()->Lock();
							AddList(&list);
							Window()->Unlock();

							update_self();

							Window()->Lock();
							SortItems(&Sorter);
							Window()->Unlock();
						};

			void			SelectionChanged()
						{
							if((CurrentSelection()>=0) && (CurrentSelection()<CountItems()))
							{
								PListItem *i=(PListItem *)ItemAt(CurrentSelection());
								inst->iview->UpdateFile(i->Path());
							}
							else
							{
								inst->iview->Clear();
							}	
						};
												
			void			SelectNext()
						{
							int32 newselection=CurrentSelection()+1;
							if(newselection>(CountItems()-1)) newselection=0;	
							Select(newselection);
						};
						
			void			SelectPrev()
						{
							int32 newselection=CurrentSelection()-1;
							if(newselection<0) newselection=CountItems()-1;	
							Select(newselection);
						};

			void			KeyDown(const char *data, int32 num)
						{
							int32 i;
							switch(data[0])
							{
								case		B_FUNCTION_KEY:
										{
											key_info ki;				
											get_key_info(&ki);
											int i=0;
											
											if ( (ki.key_states[B_F1_KEY>>3] & (1<<(7-(B_F1_KEY%8)))) )
											{
												i=0;
											}
											else if ( (ki.key_states[B_F2_KEY>>3] & (1<<(7-(B_F2_KEY%8)))) )
											{
												i=1;
											}
											else if ( (ki.key_states[B_F3_KEY>>3] & (1<<(7-(B_F3_KEY%8)))) )
											{
												i=2;
											}
											else if ( (ki.key_states[B_F4_KEY>>3] & (1<<(7-(B_F4_KEY%8)))) )
											{
												i=3;
											}
											else if ( (ki.key_states[B_F5_KEY>>3] & (1<<(7-(B_F5_KEY%8)))) )
											{
												i=4;
											}
											else if ( (ki.key_states[B_F6_KEY>>3] & (1<<(7-(B_F6_KEY%8)))) )
											{
												i=5;
											}
											else if ( (ki.key_states[B_F7_KEY>>3] & (1<<(7-(B_F7_KEY%8)))) )
											{
												i=6;
											}
											else if ( (ki.key_states[B_F8_KEY>>3] & (1<<(7-(B_F8_KEY%8)))) )
											{
												i=7;
											}
											else if ( (ki.key_states[B_F9_KEY>>3] & (1<<(7-(B_F9_KEY%8)))) )
											{
												i=8;
											}
											else if ( (ki.key_states[B_F10_KEY>>3] & (1<<(7-(B_F10_KEY%8)))) )
											{
												i=9;
											}
											else if ( (ki.key_states[B_F11_KEY>>3] & (1<<(7-(B_F11_KEY%8)))))
											{
												i=10;
											}
											else if ( (ki.key_states[B_F12_KEY>>3] & (1<<(7-(B_F12_KEY%8)))))
											{
												i=11;
											}
											if(i<CountItems())
											{
												Select(i);
												Invoke(NULL);
											}
										}
										break;
								case		B_DOWN_ARROW:
										SelectNext();
										break;
								case		B_UP_ARROW:
										SelectPrev();
										break;
								case		B_LEFT_ARROW:
										SelectPrev();
										Invoke(NULL);
										break;
								case		B_RIGHT_ARROW:
										SelectNext();
										Invoke(NULL);
										break;
								case		B_ENTER:
										Invoke(NULL);
										break;
								case		's':
								case		'S':
								case		B_ESCAPE:
										inst->dual_object->DoMethod(D_STOP);
										break;
								case		'P':
								case		'p':
										inst->dual_object->DoMethod(D_PLAY);
										break;
							}
						};

	private:

			void			Draw(BRect rect)
						{
							BListView::Draw(rect);
							Sync();
						};

			void			FrameResized(float x, float y)
						{
							BListView::FrameResized(x,y);
							bar->MoveTo(Frame().RightTop()+BPoint(1,0));
							bar->ResizeTo(B_V_SCROLL_BAR_WIDTH,Frame().RightBottom().y);
						};
	
			void			update_self()
						{
							Window()->Lock();
							float foo=ItemFrame(CountItems()-1).bottom+ITEM_HEIGHT;
							bar->SetProportion(Bounds().Height()/foo);
							foo-=Bounds().Height();
							if(foo<0)foo=0;
							bar->SetRange(0,foo);
							bar->SetSteps(ITEM_HEIGHT,Bounds().Height());
							Window()->Unlock();
							inst->dual_object->DoMethod(D_NEW_FASTCNT,CountItems());
							inst->dual_object->DoMethod(D_NEW_PLAYLIST_STATUS);
						};
};	

// Directory view, left view
class DListView : public BListView
{
	private:
	
	BPopUpMenu			*pop;
	BScrollBar 			*bar;
	BMessenger			*bm;
	bigtime_t				db;
	BFilePanel 			*fpanel;
	MyFilter				filter;
	int32				sorttype;	
	BMenuItem				*sreve;	
	instance_struct		*inst;

	public:
						DListView(instance_struct *i, BRect frame):BListView(frame,"DListView",B_SINGLE_SELECTION_LIST,B_FOLLOW_NONE)
						{
							inst=i;

							if(inst->prefs->FindInt32("CollectorDirSort",&sorttype)!=B_NO_ERROR)
							{
								sorttype=SORT_NAME;
							}

							SetFlags( Flags() | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE );
							db=0;
						};
						
	 		char 		*extract_name(char *path)
						{
							int32 c=strlen(path);
							int32 pos=0;
							
							for(int32 i=0;i<c;i++)
								if(path[i]=='/') pos=i+1;
						
							return &path[pos];
						};

	inline	int32		SortType()
						{
							return sorttype;
						};

	static	int			Sorter(const void *v1, const void *v2)
	 					{
	 						DListItem *i1=*((DListItem **)v1);
	 						DListItem *i2=*((DListItem **)v2);
	 						
	 						if(i1->Container()->SortType() & SORT_REVERSE)
	 						{
	 							return strcasecmp(i2->Container()->extract_name(i2->Path()),i1->Container()->extract_name(i1->Path()));
	 						}
	 						else
	 						{
	 							return strcasecmp(i1->Container()->extract_name(i1->Path()),i2->Container()->extract_name(i2->Path()));
	 						}
	 					};

			void			AttachedToWindow()
						{
							BPopUpMenu *menu = new BPopUpMenu("Dir",FALSE,FALSE);
							BMenuItem  *item;
							
							item = new BMenuItem("Set Base Directory…", new BMessage(LST_BASEDIR));
							menu->AddItem(item);	
							item = new BMenuItem("Rename…", new BMessage(LST_RENAME));
							menu->AddItem(item);
//							item = new BMenuItem("Delete", new BMessage(LST_DELETE),NULL);
//							menu->AddItem(item);
							menu->AddItem(new BSeparatorItem());
							sreve = item = new BMenuItem("Reverse Sorting", new BMessage(LST_REVERSE));
							menu->AddItem(item);							
							menu->SetTargetForItems(this);

							if(sorttype&SORT_REVERSE)
							{
								sreve->SetMarked(TRUE);
							}
							
							pop=menu;

							bar	= new BScrollBar(BRect(Frame().RightTop()+BPoint(1,0),Frame().RightBottom()+BPoint(B_V_SCROLL_BAR_WIDTH,0)),"",this,0,0,B_VERTICAL);
							Window()->AddChild(bar);
							bar->SetResizingMode(B_FOLLOW_NONE);
							bar->SetFlags( bar->Flags() | B_FULL_UPDATE_ON_RESIZE );
							SetLowColor(200,200,200);
							SetViewColor(200,200,200);
							update_self();
							BListView::AttachedToWindow();
							SetFont(be_plain_font);
							SetFontSize(9);
							MakeFocus();
							
							bm = new BMessenger(this);
							fpanel = new BFilePanel(B_OPEN_PANEL,NULL,NULL,B_DIRECTORY_NODE);
							fpanel->SetTarget(*bm);
							fpanel->SetMessage(new BMessage(LST_SETDIR));	
							fpanel->SetRefFilter(&filter);
						};
						
			void			MessageReceived(BMessage *msg)
						{
							switch(msg->what)
							{				
								case		LST_BASEDIR:
										fpanel->Show();
										return;

								case		'NDMN':
										{
											int32 opcode;
											if(msg->FindInt32("opcode",&opcode)==B_NO_ERROR)
											{
												switch(opcode)
												{
													case		B_ENTRY_CREATED:
													case		B_ENTRY_REMOVED:
													case		B_ENTRY_MOVED:
													case		B_STAT_CHANGED:
													case		B_ATTR_CHANGED:
															UpdateBaseDirectory();
															break;
												}
											}
										}
										return;								
								case		LST_REVERSE:
										if(sorttype&SORT_REVERSE)
										{
											sorttype&=0xF;
											sreve->SetMarked(FALSE);
										}
										else
										{	
											sorttype|=SORT_REVERSE;
											sreve->SetMarked(TRUE);
										}
										inst->prefs->ReplaceInt32("CollectorDirSort",sorttype);
										SortItems(&Sorter);
										break;
								case		'RENA':
										{
											const char *tmp;
											msg->FindString("Name",&tmp);
											
											if((CurrentSelection()>=0) && (CurrentSelection()<CountItems()))
											{	
												DListItem *i=(DListItem *)ItemAt(CurrentSelection());
												
												BEntry entry = BEntry(i->Path());
												entry.Rename(tmp);
											}
										}
										break;										
								case		LST_RENAME:
										{
											if((CurrentSelection()>=0) && (CurrentSelection()<CountItems()))
											{	
												PListItem *i=(PListItem *)ItemAt(CurrentSelection());
												requester->Prepare(this,extract_name(i->Path()));
												requester->Show();
											}
										}
										break;
							}
							
							if(msg->WasDropped() || msg->what==LST_SETDIR )
							{
								entry_ref ref;
								if(msg->FindRef("refs",&ref)==B_NO_ERROR)
								{
									BEntry entry = BEntry(&ref);
									if(entry.IsDirectory())
									{
										BPath path = BPath();
										entry.GetPath(&path);
										inst->prefs->ReplaceString("CollectorBase",path.Path());
										UpdateBaseDirectory();
										return;
									}
								}
							}
							
							BView::MessageReceived(msg);	
						};
			
			void			MouseDown(BPoint where)
						{
							BPoint moved;
							uint32 buttons,index;
							int64 clickspeed;
						
							ConstrainClippingRegion(NULL);
						
							get_click_speed(&clickspeed);
						
							GetMouse(&where,&buttons);
						
							if(buttons&B_SECONDARY_MOUSE_BUTTON)
							{
								pop->Go(ConvertToScreen(where)-BPoint(2,2),TRUE,TRUE,Frame());
								return;		
							}
						
							index=IndexOf(where);
							if(index!=CurrentSelection())
							{
								Select(index);
								db=0;
							}
							if((system_time()-db)<clickspeed)
							{	
								Invoke(NULL);
								db=0;	
							}
							else
							{
								db=system_time();
							}
						}

			void			KeyDown(const char *data, int32 num)
						{
							inst->plist->KeyDown(data,num);
						};

							
			void			FrameResized(float x, float y)
						{
							BListView::FrameResized(x,y);
							bar->MoveTo(Frame().RightTop()+BPoint(1,0));
							bar->ResizeTo(B_V_SCROLL_BAR_WIDTH,Frame().RightBottom().y);
						};
						
			void			SelectionChanged()
						{
							DListItem *i=(DListItem *)ItemAt(CurrentSelection());
							if(i)inst->plist->UpdateDirectory(i->Path());
						};

			void			ShowNextDir()
						{
							int32 newselection=CurrentSelection()+1;
							if(newselection>(CountItems()-1)) newselection=0;	
							Select(newselection);
						};
						
			void			ShowPrevDir()
						{
							int32 newselection=CurrentSelection()-1;
							if(newselection<0) newselection=CountItems()-1;	
							Select(newselection);
						};
							
			void			UpdateBaseDirectory()
						{
							DListItem *i;	

							while(i=(DListItem *)RemoveItem((int32)0))delete i;

							stop_watching(this); 
							
							node_ref node;
							BEntry file = BEntry();
							BPath path = BPath();
							BDirectory dir = BDirectory(inst->prefs->FindString("CollectorBase"));
							BEntry stat = BEntry(inst->prefs->FindString("CollectorBase"));

							stat.GetNodeRef(&node);
							watch_node(&node,B_WATCH_DIRECTORY|B_WATCH_NAME|B_WATCH_STAT,this);

							dir.Rewind();
							while(dir.GetNextEntry(&file)==B_NO_ERROR)
							{
								file.GetPath(&path);
								i = new DListItem(this);
								i->SetPath(path.Path());
								Window()->Lock();
								AddItem(i);
								Window()->Unlock();
							}
							Window()->Lock();
							SortItems(&Sorter);
							Window()->Unlock();
							update_self();
						}
	private:

			void			Draw(BRect rect)
						{
							BListView::Draw(rect);
							Sync();
						};
	
			void			update_self()
						{
							Window()->Lock();
							float foo=ItemFrame(CountItems()-1).bottom+ITEM_HEIGHT;
							bar->SetProportion(Bounds().Height()/foo);
							foo-=Bounds().Height();
							if(foo<0)foo=0;
							bar->SetRange(0,foo);
							bar->SetSteps(ITEM_HEIGHT,Bounds().Height());
							Window()->Unlock();
							inst->dual_object->DoMethod(D_NEW_FASTCNT,CountItems());
							inst->dual_object->DoMethod(D_NEW_PLAYLIST_STATUS);
						};
};	

// Main window
class MikListWindow : public BWindow
{
	private:
	
		bool				already;
		bool				quit;
		bool				clear;
		instance_struct	*inst;
		PListView			*plist;
		DListView			*dlist;
		InfoView			*iview;
	
	public:	
						MikListWindow(instance_struct *i, BRect frame):BWindow(frame,"Collector",B_TITLED_WINDOW, NULL)
						{	
							inst=i;
							
							requester = new StringRequester();
								
							dlist = new DListView(inst,BRect(0,0,frame.Width()/3-B_V_SCROLL_BAR_WIDTH,frame.Height()));
							plist = new PListView(inst,BRect(frame.Width()/3+1,0,(frame.Width()/3)*2-B_V_SCROLL_BAR_WIDTH,frame.Height()));
							iview = new InfoView(inst,BRect(frame.Width()/3*2+1,0,frame.Width(),frame.Height()));
							
							AddChild(iview);
							AddChild(plist);
							AddChild(dlist);
							
							inst->plist=plist;
							inst->dlist=dlist;
							inst->iview=iview;
							
							Run();
						
							dlist->UpdateBaseDirectory();
						
							SetSizeLimits(iview->MinSize().x*3+B_V_SCROLL_BAR_WIDTH*2,2000,iview->MinSize().y,2000);
						
						}

			void			FrameResized(float width, float height)
						{
							BRect frame=Frame();
							dlist->MoveTo(0,0);
							dlist->ResizeTo(frame.Width()/3-B_V_SCROLL_BAR_WIDTH-1,frame.Height());
							plist->MoveTo(frame.Width()/3+1,0);
							plist->ResizeTo(frame.Width()/3-B_V_SCROLL_BAR_WIDTH-2,frame.Height());
							iview->MoveTo(frame.Width()/3*2+1,0);
							iview->ResizeTo(frame.Width()/3,frame.Height());
						};
						
			void 		MessageReceived(BMessage *msg)
						{
							switch(msg->what)
							{
								case		WIN_SHOWW:
										Show();
										break;
						
								case		WIN_HIDEW:
										Hide();
										break;	

							}
						};
						

			void			KeyDown(const char *data, int32 num)
						{
							plist->KeyDown(data,num);
						};
						
			bool			QuitRequested()
						{
							if(quit)
							{
								if(!already)
								{
									inst->prefs->RemoveName("CollectorWindow");
									inst->prefs->AddRect("CollectorWindow",Frame());
									already=TRUE;
									
									release_sem(inst->close_sem);
								}
							}
							else
							{
								Hide();
								inst->dual_object->DoMethod(D_NEW_PLAYLIST_STATUS);
							}
							if(quit)	return TRUE;
							else		return FALSE;
						};
						
			void			SelectNext()
						{
							Lock();
							plist->SelectNext();
							Unlock();
						};
						
			void			SelectPrev()
						{
							Lock();
							plist->SelectPrev();
							Unlock();
						};
						
			void			PlaySelect(int32 num)
						{
							Lock();
							plist->Select(num);
							plist->Invoke(NULL);	
							Unlock();
						};
						
			void			PlayNext()
						{
							Lock();
							plist->SelectNext();
							plist->Invoke(NULL);
							Unlock();
						};
						
			void			PlayPrev()
						{
							Lock();
							plist->SelectPrev();
							plist->Invoke(NULL);
							Unlock();
						};
						
			void			PlayCurrent()
						{
							Lock();
							plist->Invoke(NULL);
							Unlock();
						};
						
			bool			ListUsed()
						{
							if(plist->CountItems()>0) return true;
						};
						
			void			Select(int32 num)
						{
							Lock();
							plist->Select(num);
							Unlock();
						};
						
			int			CountItems(void)
						{
							return plist->CountItems();
						};
						
			void			AllowQuit(bool q)
						{
							quit=q;
						};
				
			void			Refresh(void)
						{
						
						};		
};

// Dispatcher of our Zoonic class
long class_dispatcher(Class *c, Object *o, ulong MethodID, ulong *data)
{
	instance_struct *inst=(instance_struct *)o->Instance(c);
	
	o->SetError(B_NO_ERROR);
		
	switch(MethodID)
	{
		case		B_METHOD_CONSTRUCT:	// void (void)
				{					
					inst->prefs = NULL;
					inst->list = NULL;
					
					return 0;
				}

		case		B_METHOD_DESTROY:	// void (void)
				{
					return 0;
				}		
		
		case		PL_ACTIVATE:		// void (void)						
				{
					inst->close_sem=create_sem(0,"close_sem");
				
					BRect frame=BRect(20,40,120,140);
					
					inst->prefs->FindRect("CollectorWindow",&frame);
					inst->list=new MikListWindow(inst,frame);
					inst->list->AllowQuit(FALSE);
					
					return 0;
				}		

		case		PL_DISACTIVATE:		// void (void)						
				{
					inst->list->AllowQuit(TRUE);
					inst->list->PostMessage(B_QUIT_REQUESTED);
					inst->list=0;
					acquire_sem(inst->close_sem);
					delete_sem(inst->close_sem);
					inst->close_sem=0;
									
					return 0;
				}		

		case		PL_SHOW:			// void (void)						
				{
					if(inst->list->IsHidden())inst->list->Show();		
					return 0;
				}		

		case		PL_HIDE:			// void (void)						
				{
					if(!inst->list->IsHidden())inst->list->Hide();		
					return 0;
				}		

		case		PL_REFRESH:			// void (void)						
				{
					inst->list->Refresh();
					return 0;
				}		

		case		PL_PLAYNEXT:		// void (void)						
				{
					inst->list->PlayNext();
					return 0;
				}		

		case		PL_PLAYPREV:		// void (void)						
				{
					inst->list->PlayPrev();
					return 0;
				}		

		case		PL_PLAYCURRENT:		// voif (void)						
				{
					inst->list->PlayCurrent();
					return 0;
				}		

		case		PL_PLAYNUM:			// void (int32 num)					
				{
					inst->list->PlaySelect(data[0]);
					return 0;
				}		

		case		PL_PLAYRANDOM:
				{
					int32 play;
					int32 num;
					num=inst->list->CountItems();
					if(num>0)
					{
						play=(rand()*num)/RAND_MAX;
						inst->list->PlaySelect(play);
					}
					return 0;
				}				

		case		PL_KEYDOWN:			// void (char *data, int32 num)			
				{
					inst->list->Lock();
					inst->list->KeyDown((char *)data[0],(int32)data[1]);
					inst->list->Unlock();
					return 0;
				}		
								
		case		PL_SETATTR:			//  void (ulong AttributeID, ulong data)
				{
					ulong ATTR =(ulong)data[0];
					ulong DATA =(ulong)data[1];
					
					switch(ATTR)
					{
						case		PL_ATTR_PREFS:				
								inst->prefs=(BMessage *)DATA;
								if(!inst->prefs->HasRect("CollectorWindow"))
									inst->prefs->AddRect("CollectorWindow",BRect(383,37,600,300));
								if(!inst->prefs->HasString("CollectorBase"))
									inst->prefs->AddString("CollectorBase","/boot");
								if(!inst->prefs->HasInt32("CollectorDirSort"))
									inst->prefs->AddInt32("CollectorDirSort",SORT_NAME);
								if(!inst->prefs->HasInt32("CollectorFileSort"))
									inst->prefs->AddInt32("CollectorFileSort",SORT_NAME);
								break;
								
						case		PL_ATTR_DUALOBJECT:
								inst->dual_object=(Object *)DATA;
								break;
								
					}
					o->DoSuperMethod(c,PL_SETATTR,data);
					return 0;
				}
						
		case		PL_GETATTR:			//	void (ulong AttributeID, ulong data)
				{
					ulong ATTR =(ulong)data[0];
					ulong DATA =(ulong)data[1];

					switch(ATTR)
					{
						case		PL_ATTR_ID:					
								*((const char **)DATA)=PLAYLIST_NAME;
								return 0;
								
						case		PL_ATTR_ISHIDDEN:
								if(inst->list)
								{
									if(inst->list->IsHidden())
										*((int32 *)DATA)=TRUE;
									else
										*((int32 *)DATA)=FALSE;
								}
								return 0;

						case		PL_ATTR_NUMENTRIES:
								if(inst->list)
								{
									*((int32 *)DATA)=inst->list->CountItems();
								}
								return 0;

						case		PL_ATTR_LISTUSED:
								if(inst->list)
								{
									if(inst->list->CountItems()>0)
										*((int32 *)DATA)=TRUE;
									else
										*((int32 *)DATA)=FALSE;									
								}
								return 0;
								
						default:
								return o->DoSuperMethod(c,PL_GETATTR,data);
					}
				}
				
		default:
				return o->DoSuperMethod(c,MethodID,data);
	}
}

char *class_superclass()
{
	return (char *)pl_superclass;
};

long class_instancesize()
{
	return sizeof(struct instance_struct);
};

long class_superversion()
{
	return pl_version;
};

long class_version()
{
	return 1;
};
