#ifndef REFLOWING_TEXT_VIEW_H
#define REFLOWING_TEXT_VIEW_H

#include <app/AppDefs.h>
#include <app/Application.h>
#include <app/Roster.h>
#include <app/MessageFilter.h>
#include <app/Message.h>
#include <app/Messenger.h>
#include <interface/TextView.h>

#include "util/Queue.h"
#include "BeShareNameSpace.h"

namespace beshare {

/* Subsclass of BTextView that automatically reflows the text when it is resized */
class ReflowingTextView : public BTextView
{
public:
   ReflowingTextView(BRect frame, const char *name, BRect textRect, uint32 resizeMask, uint32 flags = B_WILL_DRAW | B_PULSE_NEEDED)
      : BTextView(frame, name, textRect, resizeMask, flags)
   {
      // empty
   }

   virtual void AttachedToWindow()
   {
      BTextView::AttachedToWindow();
      FixTextRect();
   }
  
   virtual void FrameResized(float w, float h)
   {
      BTextView::FrameResized(w, h);
      FixTextRect();
   }
 
   virtual void MouseMoved(BPoint where, uint32 code, const BMessage * msg)
   {
      uint32 start, len;
      if (code == B_INSIDE_VIEW) 
      {
#ifdef B_BEOS_VERSION_5
         SetViewCursor(GetURLAt(where, start, len) ? B_CURSOR_SYSTEM_DEFAULT : B_CURSOR_I_BEAM);
#else
         be_app->SetCursor(GetURLAt(where, start, len) ? B_HAND_CURSOR : B_I_BEAM_CURSOR);
#endif
      }
      BTextView::MouseMoved(where, code, msg);
   }

   virtual void MouseDown(BPoint where)
   {
      if (IsFocus() == false) MakeFocus();
      uint32 start, len;
      if (GetURLAt(where, start, len))
      {
          String url;
          char * buf = new char[len+1];
          GetText(start, len, buf);
          buf[len] = '\0';
          if (strncasecmp(buf, "beshare:", 8) == 0)
          {
             BMessage msg(_queryMessage);
             msg.AddString("query", &buf[8]);
             _commandTarget.SendMessage(&msg);
          }
          else if (strncasecmp(buf, "priv:", 5) == 0)
          {
             BMessage msg(_privMessage);
             msg.AddString("users", &buf[5]);
             _commandTarget.SendMessage(&msg);
          }
          else if (strncasecmp(buf, "audio://", 8) == 0)
          {
             BMessage msg(B_REFS_RECEIVED);
             String temp("http://");
             temp += &buf[8];
             msg.AddString("be:url", temp.Cstr());
             be_roster->Launch("audio/x-scpls", &msg);
          }
          else be_roster->Launch(strncasecmp(buf, "mailto:", 7) ? "text/html" : "text/x-email", 1, &buf);

          delete [] buf;
      }
      BTextView::MouseDown(where);
   }

   void FixTextRect()
   {
      BRect t(Frame());
      SetTextRect(t);
   }

   void Clear()
   {
      Delete(0, TextLength()-1);
      _urls.Clear();
   }

   void AddURLRegion(uint32 start, uint32 len)
   {
      uint64 s = start;
      uint64 l = len;
      _urls.AddTail((s<<32)|l);      
   }

   void SetCommandURLTarget(const BMessenger & target, const BMessage & queryMsg, const BMessage & privMsg)
   {
      _commandTarget = target;
      _queryMessage  = queryMsg;
      _privMessage   = privMsg;
   }

private:
   bool GetURLAt(BPoint pt, uint32 & retStart, uint32 & retLen) const
   {
      uint32 offset = (uint32) OffsetAt(pt);
      for (int i=_urls.GetNumItems()-1; i>=0; i--)
      {
         uint64 code = _urls[i];
         uint32 start = (uint32) (code >> 32);
         uint32 len   = (uint32) (code & 0xFFFFFFFF);
         if ((offset >= start)&&(offset < start + len))
         {
            retStart = start;
            retLen = len;
            return true;
         }
      }
      return false;
   }

   Queue<uint64> _urls;
   BMessenger _commandTarget;
   BMessage _queryMessage;
   BMessage _privMessage;
};
      
};  // end namespace beshare

#endif
