// This may look like C code, but it is really -*- C++ -*-

//<copyright>
//
// Copyright (c) 1994,95
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
//
//</copyright>

//<file>
//
// Name:        imgserver.h
//
// Purpose:     server for texture images and URLs
//
// Created:     16 Mar 94   Gaisbauer Mansuet Juergen
//
// Changed:      3 Nov 95   Michael Pichler
//                          * no image caching,
//                          * sequential order of fetching images
//
//
//</file>


#ifndef hg_viewer_scene_imgserver_h
#define hg_viewer_scene_imgserver_h

#include <hyperg/utils/str.h>
#include <hyperg/hyperg/object.h>

#include <Dispatch/rpcservice.h>
#include <Dispatch/iohandler.h>
#include <Dispatch/iocallback.h>

#include "slist.h"

#include <fstream.h>

class Material;
class QvWWWInline;

class HgViewerManager;
class ImageServer;
class ImageRequest;
class InlineURLRequest;


//<class>
//
// Name: ImageReader
//
//</class>

class ImageReader: public IOHandler
{
  public:
    ImageReader (int fd, ImageServer* server);
    ~ImageReader ();

    virtual int inputReady (int fd);

  private:
    enum
    { request,
      header_ok,
      no_header
    } header_state_;

    int pipe_port_;

    ImageServer* server_;

    RString filename_;

    ofstream ostr_;

    static char* rd_buf_;
    static unsigned int img_reader_no_;

  friend class ImageServer;

}; // ImageReader



class ImageServerCallback
{
  public:
    // fetching data:
    virtual int readImage (Material* mat, const char* filename) = 0;
    // return 0 to continue, or 1 to stop reading

    virtual int readInlineURL (QvWWWInline* node, const char* filename) = 0;
    // return 0 to continue, or 1 to stop reading

    // feedback:
    virtual void requestImage (const Material* mat) = 0;
    virtual void requestURL (const QvWWWInline* node) = 0;
    virtual void requestFinished () = 0;
};


//<class>
//
// Name:     ImageServer
//
//</class>


class ImageServer: public RpcService
{
  public:
    ImageServer (
      HgViewerManager* manager,
      ImageServerCallback* callback
    );
    ~ImageServer ();

    void clearAllRequests ();           // cancel all current requests

    void cancelRequest (                // cancel specific request
      const char*                       //   ref.number (string)
    );

    void appendRequest (                // request for texture image
      const RString& doc_id,            //   document ID
      const Object& anchor_obj,         //   anchor object
      const RString& dest,              //   destination (string)
      Material* mat                     //   material (where to store texture)
    );
//    ImgReq* removeImgReq (long refno);

    void parseURL (const char* url,     // parse an URL
      const char* docurl,               //   URL of requesting document (for local URLs)
      RString& msg                      //   and build a Hyper-G object string
    );
    // object string contains: DocumentID 0, unused ObjectID, Type,
    // DocumentType, RemoteType, Protocol, Host, Port, Path, WWWType, Title;
    // caller may append WWWType, LinkType, PipePort, PipeHost

    void requestInlineURL (             // URL-request for inline VRML
      QvWWWInline* node,                //   node (where attach inline data)
      const char* url,                  //   requested URL (of data to be fetched)
      const char* docurl                //   URL of requesting document (for local URLs)
    );

    void handleRequests (int texturesalso);

//     ImgLoaderCallbacks* getCallbacks() { return callbacks_; };
//     void setCallbacks(ImgLoaderCallbacks* cb) { callbacks_ = cb; };

    // RpcService
    virtual void createReader (int fd);

//     virtual int reqCount() { 
//       return reader_list_.count() + req_list_.count(); 
//     };
//     virtual int imgCount() {
//       return image_list_.count();
//     };

    const RString& getPath () const  { return path_; }

  private:
    void removeReader(ImageReader* reader);  // reader finished, will be destroyed

    void insertCache(long, long);

    boolean idIsRequested(const RString& doc_id);

    int req_without_connect_;   // number of requests without a reader; no
                                // connect has happend; is not equal to
                                // req_list_.count() because requests will
                                // be removed from this list if the image is
                                // identified by a header, but left in the list
                                // otherwise

    ImageRequest* pendingimgrequest_;   // pending image request
    slist imagerequests_;               // list of ImageRequest

    InlineURLRequest* pendingurlrequest_;  // pending URL (inline VRML) request
    slist urlrequests_;                 // list of InlineURLRequest

//     ImgReqList req_list_;       // list of requests, which are not assigned
//                                 // to an image via a header
//     ImgList image_list_;        // list of received images, which maybe 
//                                 // allready assigned to a request (after
//                                 // identifying them via a header)

    int requesttextures_;               // whether to load texture images too

    ImageReader* imgreader_;

    HgViewerManager* manager_;
    RString path_;

    ImageServerCallback* callback_;

    static long refno_;                 // free refno for WWW anchors

  friend class ImageReader;

}; // ImageServer


#endif
