// Emacs: -*- C++ -*-

//
//	Copyright 1993, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//


//
// $Log: ImageDisplayProtocol.h,v $
// Revision 1.5  1993/06/10  17:17:10  thoth
// Solaris adjustments
//
// Revision 1.4  93/05/27  15:04:13  thoth
// Copyright Notices
// 
// Revision 1.3  93/05/26  16:05:41  thoth
// Array is now IA_Array.
// 
// Revision 1.2  92/11/19  01:19:42  thoth
// Flubber solves packet length problem (what a hack!)
// 
// Revision 1.1  92/11/18  15:35:28  thoth
// Initial revision
// 
//

#ifndef ImageDisplayProtocol_h_
#define ImageDisplayProtocol_h_

#include "Array.h"

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>

class IDP {
  enum PacketType {
      NewClientRequest,
	  CreateDisplayRequest,
	  PickDisplayRequest,
	  DeleteDisplayRequest,
	  ReleaseDisplayRequest,
	  WriteImageRequest,
	  ReadImageRequest,
	  MoveImageRequest,
	  GetRegionDisplayedRequest,
	  WriteZoomRequest,
	  ReadZoomRequest,
	  SelectPointRequest,
	  WriteROIRequest,
	  SelectROIRequest,
	  WriteLUTRequest,
	  ReadLUTRequest,
	  
	  NewClientReturn,
	  CreateDisplayReturn,
	  PickDisplayReturn,
	  DeleteDisplayReturn,
	  ReleaseDisplayReturn,
	  WriteImageReturn,
	  ReadImageReturn,
	  MoveImageReturn,
	  GetRegionDisplayedReturn,
	  WriteZoomReturn,
	  ReadZoomReturn,
	  SelectPointReturn,
	  WriteROIReturn,
	  SelectROIReturn,
	  WriteLUTReturn,
	  ReadLUTReturn,
	  
	  ErrorReturn,
	  ReadImageFileRequest,
	  ReadimageFileReturn,
	  WriteImageFileRequest,
	  WriteImageFileReturn
	  };
  
  struct PacketHeader {
  private:
    static int my_version;
  public:
    char	align[4];
    int		len;
    int		type; // store a PacketType in here
    int		version;
    PacketHeader() {
	align[0] = 'C';
	align[1] = 'B';
	align[2] = 0;
	align[3] = 0;
	version = my_version; // this is what IAA does
    }
    PacketHeader(PacketType type_) {
	align[0] = 'C';
	align[1] = 'B';
	align[2] = 0;
	align[3] = 0;
	type = type_;
	version = my_version; // this is what IAA does
    }
    int is_valid() const {
	return align[0]=='C' && align[1]=='B' && version==my_version;
    }
  };

public:
  enum ImageType {
      U_BYTE, FLOAT, BINARY, COMPLEX
      };
  static const unsigned ImageTypeSizes[4];
  static const unsigned maxdims;

private:
  typedef char	Label[100];
  typedef char	DeviceName[64];

#if 1
  union PacketBody {
    struct {
      int ptype;
      int window;
    } any;
    struct {
      int ptype;
      int window;
      Label	label;
    } new_client;
    struct {
      int ptype;
      int window;
      int	client;
      DeviceName	devname;
      int	access;
      char	flubber[1024];
    } create_display;

    struct {
      int ptype;
      int window;
      Label	label;
      ImageType	type;
      int	elt_size;
      unsigned	ndims;
      unsigned	lengths[2]; // must match IDP::maxdims
    } write_image;
    struct {
      int ptype;
      int window;
      int roi;
    } read_image;

    struct {
      int ptype;
      int window;
      int	id;
    } new_client_ret;
    struct {
      int ptype;
      int window;
      ImageType	type;
      int	elt_size;
      unsigned	ndims;
      unsigned	lengths[2]; // must match IDP::maxdims
    } read_image_ret;
#if 1
    PacketBody() { memset(this, 0, sizeof(*this)); }
#else
    PacketBody() { bzero(this, sizeof(*this)); }
#endif
  };
#else
  struct PacketBody {
    int	ptype;
    int	window;			// ada fields

    union {
      Label	new_client;
      struct {
	int	client;
	DeviceName	devname;
	int	access;
      } create_display;

      struct {
	Label	label;
	ImageType	type;
	int	elt_size;
	unsigned	ndims;
	unsigned	lengths[2]; // must match IDP::maxdims
      } write_image;
      int read_image_roi;

      int	new_client_ret;
      struct {
	ImageType	type;
	int	elt_size;
	unsigned	ndims;
	unsigned	lengths[2]; // must match IDP::maxdims
      } read_image_ret;
    };
  };
#endif

public:
  class ClientID {
    int	id;
    int	desc;
#ifdef USE_FP
    FILE	*fp;
#endif
    // friend ClientID ::IDP::NewClient(char*);
  public:
    friend class IDP;
    ClientID() {
	id = 0;
	desc = -1;
#ifdef USE_FP
	fp=0;
#endif
    }
    void close_desc() {
#ifdef USE_FP
	fclose(fp);
#else
	close(desc);
#endif
	desc = -1;
    }
    int write_bytes(const void*, unsigned);
    int read_bytes(void*, unsigned);
    
    int write_packet(PacketType type, const void *data, unsigned len);
    void *read_packet(PacketType *type, unsigned *len);
  };
  friend class ClientID;

  class LinkID {
    int	id;
    ClientID	*master;
  public:
    friend class IDP;
    LinkID(ClientID *master_=0)
    :master(master_) { id=0; }
  };

  enum Access {
      READ_WRITE, READ_ONLY, WRITE_ONLY
  };
  
private:
  static char *expect_packet(ClientID&, PacketType, unsigned *);
public:
  
  static ClientID NewClient(const char *cname);
  
  static LinkID CreateDisplay
  (ClientID &id, const char *devname, Access access);
  
  static LinkID PickDisplay(ClientID &id, const char *devname, Access access);
  
  static int DeleteDisplay(LinkID id);
  
  static int ReleaseDisplay(LinkID id);
  
  typedef unsigned char eltype;
  
  static LinkID WriteImage(LinkID id, const char *label, ImageType type,
			   unsigned elsize, IA_Array<unsigned> dimensions,
			   const void *values);
  static void *ReadImage(LinkID id, int UseROI, ImageType *type,
			   unsigned *elsize, IA_Array<unsigned> *dimensions);
  
  static LinkID MoveImage(LinkID id, IA_Array<unsigned> center);
  static LinkID WriteZoom(LinkID id, int zoom_factor);
  static LinkID WhereIsImage(LinkID id, IA_Array<unsigned> *upper_left,
			     IA_Array<unsigned> *lower_right);
  static int ReadZoom(LinkID id);
};

#endif
