
#ifndef __IMAGE_H
#define __IMAGE_H

/*
 * header files
 */
#include "p.struct.h"

@begin
   header "struct.h";
@end

/*
 * structures describing ms bitmap file
 */

/*
 * definition of structure bmp_fh_s
 */

#pragma pack(1)
struct bmp_fh_s
{
   short type;
   int size;
   short res_1;
   short res_2;
   int off_bits;
};
#pragma pack()

/*
 * definition of structure bmp_ih_s
 */

#pragma pack(1)  
struct bmp_ih_s
{
   int size;
   int width;
   int height;
   short planes;
   short bit_cnt;
   int compression;
   int image_size;
   int x_pel_per_meter;
   int y_pel_per_meter;
   int clr_used;
   int clr_important;
};
#pragma pack()

/*
 * definition of structure img_3ub_s
 */

struct img_3ub_s
{
   unsigned width;
   unsigned height;
   unsigned char *data;

   inline void init();
   inline void clear();
   inline void create(unsigned a_width,unsigned a_height);
   inline void flush_all();
   inline void swap(img_3ub_s &second);
   inline img_3ub_s &operator=(img_3ub_s &src);
   inline bool operator==(img_3ub_s &second);
   bool load_bmp_file(const char *file);
   bool save_bmp_file(const char *file);
   bool fill_color(short *color_ptr);
   bool invert(img_3ub_s &src);
   bool gray_scale(img_3ub_s &src);
   bool edge_sobel(img_3ub_s &src);
   bool blur(img_3ub_s &src);
   bool sharp(img_3ub_s &src);
   bool treshold(img_3ub_s &src,short *color_ptr);
   bool resize_width_up(img_3ub_s &src,unsigned a_width);
   bool resize_height_up(img_3ub_s &src,unsigned a_height);
   bool resize_width_down(img_3ub_s &src,unsigned a_width);
   bool resize_height_down(img_3ub_s &src,unsigned a_height);
   bool resize(img_3ub_s &src,unsigned a_width,unsigned a_height);
   bool add(img_3ub_s &first,img_3ub_s &second);
   bool sub(img_3ub_s &first,img_3ub_s &second);
   bool mul(img_3ub_s &first,img_3ub_s &second);
   bool add_color(img_3ub_s &src,short *color_ptr);
   bool sub_color(img_3ub_s &src,short *color_ptr);
   bool mul_color(img_3ub_s &src,short *color_ptr);
};

/*
 * definition of structure local_img_s
 */

struct local_img_s
{
   img_3ub_s img_3ub;
   mutex_s mutex;

   inline void init();
   inline void clear();
   inline void lock_clear(mutex_s &sp_mutex);
   inline void create(unsigned a_width,unsigned a_height);
   inline void lock_create(mutex_s &sp_mutex,unsigned a_width,unsigned a_height);
   inline void flush_all();
   inline void swap(local_img_s &second);
   inline void lock_swap(mutex_s &sp_mutex,local_img_s &second);
   inline local_img_s &set(local_img_s &src);
   inline local_img_s &lock_set(mutex_s &sp_mutex,local_img_s &src);
   inline bool compare(local_img_s &second);
   inline bool lock_compare(mutex_s &sp_mutex,local_img_s &second);
   inline void print_info();
   inline void lock_print_info(mutex_s &sp_mutex);
   inline bool load_bmp_file(const char *file);
   inline bool lock_load_bmp_file(mutex_s &sp_mutex,char *file);
   inline bool save_bmp_file(const char *file);
   inline bool lock_save_bmp_file(mutex_s &sp_mutex,char *file);
   inline bool fill_color(short *color_ptr);
   inline bool lock_fill_color(mutex_s &sp_mutex,short *color_ptr);
   inline bool invert(local_img_s &src);
   inline bool lock_invert(mutex_s &sp_mutex,local_img_s &src);
   inline bool gray_scale(local_img_s &src);
   inline bool lock_gray_scale(mutex_s &sp_mutex,local_img_s &src);
   inline bool edge_sobel(local_img_s &src);
   inline bool lock_edge_sobel(mutex_s &sp_mutex,local_img_s &src);
   inline bool blur(local_img_s &src);
   inline bool lock_blur(mutex_s &sp_mutex,local_img_s &src);
   inline bool sharp(local_img_s &src);
   inline bool lock_sharp(mutex_s &sp_mutex,local_img_s &src);
   inline bool treshold(local_img_s &src,short *color_ptr);
   inline bool lock_treshold(mutex_s &sp_mutex,local_img_s &src,short *color_ptr);

   inline bool add(local_img_s &first,local_img_s &second);
   inline bool lock_add(mutex_s &sp_mutex,local_img_s &first,local_img_s &second);
   inline bool sub(local_img_s &first,local_img_s &second);
   inline bool lock_sub(mutex_s &sp_mutex,local_img_s &first,local_img_s &second);
   inline bool mul(local_img_s &first,local_img_s &second);
   inline bool lock_mul(mutex_s &sp_mutex,local_img_s &first,local_img_s &second);

   inline bool add_color(local_img_s &src,short *color_ptr);
   inline bool lock_add_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr);
   inline bool sub_color(local_img_s &src,short *color_ptr);
   inline bool lock_sub_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr);
   inline bool mul_color(local_img_s &src,short *color_ptr);
   inline bool lock_mul_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr);
};

/*
 * inline methods of structure img_3ub_s
 */

inline void img_3ub_s::init()
{
   width = 0;
   height = 0;
   data = NULL;
}

inline void img_3ub_s::clear()
{
   if (data != NULL) {
      cfree(data);
   }

   init();
}

inline void img_3ub_s::create(unsigned a_width,unsigned a_height)
{
   if (width == a_width && height == a_height) return;

   clear();
   data = (unsigned char *)cmalloc(a_width*a_height*3);

   width = a_width;
   height = a_height;
}

inline void img_3ub_s::flush_all()
{
}

inline void img_3ub_s::swap(img_3ub_s &second)
{
   unsigned tmp_unsigned = width;
   width = second.width;
   second.width = tmp_unsigned;

   tmp_unsigned = height;
   height = second.height;
   second.height = tmp_unsigned;

   unsigned char *tmp_data = data;
   data = second.data;
   second.data = tmp_data;
}

inline img_3ub_s &img_3ub_s::operator=(img_3ub_s &src)
{
   clear();

   if (src.data == NULL) return *this;

   width = src.width;
   height = src.height;

   unsigned data_size = width*height*3;
   data = (unsigned char *)cmalloc(data_size);
   memcpy(data,src.data,data_size);

   return *this;
}

inline bool img_3ub_s::operator==(img_3ub_s &second)
{
   if (width != second.width || height != second.height) return false;
   if (data == NULL) return true;
   return (memcmp(data,second.data,width*height*3) == 0);
}

/*
 * inline methods of structure local_img_s
 */

inline void local_img_s::init()
{
   img_3ub.init();
   mutex.init();
}

inline void local_img_s::clear()
{
   img_3ub.clear();
   mutex.clear();
}

inline void local_img_s::lock_clear(mutex_s &sp_mutex)
{
   mutex.lock();
   sp_mutex.unlock();

   img_3ub.clear();

   mutex.unlock();
   mutex.clear();

   sp_mutex.lock();
}

inline void local_img_s::create(unsigned a_width,unsigned a_height)
{
   img_3ub.create(a_width,a_height);
}

inline void local_img_s::lock_create(mutex_s &sp_mutex,unsigned a_width,unsigned a_height)
{
   mutex.lock();
   sp_mutex.unlock();

   img_3ub.create(a_width,a_height);

   mutex.unlock();
   sp_mutex.lock();
}

inline void local_img_s::flush_all()
{
}

inline void local_img_s::swap(local_img_s &second)
{
   img_3ub.swap(second.img_3ub);
}

inline void local_img_s::lock_swap(mutex_s &sp_mutex,local_img_s &second)
{
   mutex.lock();
   if (&second != this) second.mutex.lock();
   sp_mutex.unlock();

   img_3ub.swap(second.img_3ub);

   mutex.unlock();
   if (&second != this) second.mutex.unlock();
   sp_mutex.lock();
}

inline local_img_s &local_img_s::set(local_img_s &src)
{
   img_3ub = src.img_3ub;

   return *this;
}

inline local_img_s &local_img_s::lock_set(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   img_3ub = src.img_3ub;

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return *this;
}

inline bool local_img_s::compare(local_img_s &second)
{
   return img_3ub == second.img_3ub;
}

inline bool local_img_s::lock_compare(mutex_s &sp_mutex,local_img_s &second)
{
   mutex.lock();
   if (&second != this) second.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub == second.img_3ub;

   mutex.unlock();
   if (&second != this) second.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline void local_img_s::print_info()
{
   printf("image: %u x %u",img_3ub.width,img_3ub.height);
}

inline void local_img_s::lock_print_info(mutex_s &sp_mutex)
{
   mutex.lock();
   sp_mutex.unlock();

   printf("image: %u x %u",img_3ub.width,img_3ub.height);

   mutex.unlock();
   sp_mutex.lock();
}

inline bool local_img_s::load_bmp_file(const char *file)
{
   return img_3ub.load_bmp_file(file);
}

inline bool local_img_s::lock_load_bmp_file(mutex_s &sp_mutex,char *file)
{
   mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.load_bmp_file(file);

   mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::save_bmp_file(const char *file)
{
   return img_3ub.save_bmp_file(file);
}

inline bool local_img_s::lock_save_bmp_file(mutex_s &sp_mutex,char *file)
{
   mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.save_bmp_file(file);

   mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::fill_color(short *color_ptr)
{
   return img_3ub.fill_color(color_ptr);
}

inline bool local_img_s::lock_fill_color(mutex_s &sp_mutex,short *color_ptr)
{
   mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.fill_color(color_ptr);

   mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::invert(local_img_s &src)
{
   return img_3ub.invert(src.img_3ub);
}

inline bool local_img_s::lock_invert(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.invert(src.img_3ub);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::gray_scale(local_img_s &src)
{
   return img_3ub.gray_scale(src.img_3ub);
}

inline bool local_img_s::lock_gray_scale(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.gray_scale(src.img_3ub);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::edge_sobel(local_img_s &src)
{
   return img_3ub.edge_sobel(src.img_3ub);
}

inline bool local_img_s::lock_edge_sobel(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.edge_sobel(src.img_3ub);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::blur(local_img_s &src)
{
   return img_3ub.blur(src.img_3ub);
}

inline bool local_img_s::lock_blur(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.blur(src.img_3ub);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::sharp(local_img_s &src)
{
   return img_3ub.sharp(src.img_3ub);
}

inline bool local_img_s::lock_sharp(mutex_s &sp_mutex,local_img_s &src)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.sharp(src.img_3ub);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::treshold(local_img_s &src,short *color_ptr)
{
   return img_3ub.treshold(src.img_3ub,color_ptr);
}

inline bool local_img_s::lock_treshold(mutex_s &sp_mutex,local_img_s &src,short *color_ptr)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.treshold(src.img_3ub,color_ptr);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::add(local_img_s &first,local_img_s &second)
{
   return img_3ub.add(first.img_3ub,second.img_3ub);
}

inline bool local_img_s::lock_add(mutex_s &sp_mutex,local_img_s &first,local_img_s &second)
{
   mutex.lock();

   if (&first != this) {
      first.mutex.lock();
      if (&second != this && &second != &first) second.mutex.lock();
   }
   else {
      if (&second != this) second.mutex.lock();
   }

   sp_mutex.unlock();

   bool result = img_3ub.add(first.img_3ub,second.img_3ub);

   mutex.unlock();

   if (&first != this) {
      first.mutex.unlock();
      if (&second != this && &second != &first) second.mutex.unlock();
   }
   else {
      if (&second != this) second.mutex.unlock();
   }

   sp_mutex.lock();

   return result;
}

inline bool local_img_s::sub(local_img_s &first,local_img_s &second)
{
   return img_3ub.sub(first.img_3ub,second.img_3ub);
}

inline bool local_img_s::lock_sub(mutex_s &sp_mutex,local_img_s &first,local_img_s &second)
{
   mutex.lock();

   if (&first != this) {
      first.mutex.lock();
      if (&second != this && &second != &first) second.mutex.lock();
   }
   else {
      if (&second != this) second.mutex.lock();
   }

   sp_mutex.unlock();

   bool result = img_3ub.sub(first.img_3ub,second.img_3ub);

   mutex.unlock();

   if (&first != this) {
      first.mutex.unlock();
      if (&second != this && &second != &first) second.mutex.unlock();
   }
   else {
      if (&second != this) second.mutex.unlock();
   }

   sp_mutex.lock();

   return result;
}

inline bool local_img_s::mul(local_img_s &first,local_img_s &second)
{
   return img_3ub.mul(first.img_3ub,second.img_3ub);
}

inline bool local_img_s::lock_mul(mutex_s &sp_mutex,local_img_s &first,local_img_s &second)
{
   mutex.lock();

   if (&first != this) {
      first.mutex.lock();
      if (&second != this && &second != &first) second.mutex.lock();
   }
   else {
      if (&second != this) second.mutex.lock();
   }

   sp_mutex.unlock();

   bool result = img_3ub.mul(first.img_3ub,second.img_3ub);

   mutex.unlock();

   if (&first != this) {
      first.mutex.unlock();
      if (&second != this && &second != &first) second.mutex.unlock();
   }
   else {
      if (&second != this) second.mutex.unlock();
   }

   sp_mutex.lock();

   return result;
}

inline bool local_img_s::add_color(local_img_s &src,short *color_ptr)
{
   return img_3ub.add_color(src.img_3ub,color_ptr);
}

inline bool local_img_s::lock_add_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.add_color(src.img_3ub,color_ptr);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::sub_color(local_img_s &src,short *color_ptr)
{
   return img_3ub.sub_color(src.img_3ub,color_ptr);
}

inline bool local_img_s::lock_sub_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.sub_color(src.img_3ub,color_ptr);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

inline bool local_img_s::mul_color(local_img_s &src,short *color_ptr)
{
   return img_3ub.mul_color(src.img_3ub,color_ptr);
}

inline bool local_img_s::lock_mul_color(mutex_s &sp_mutex,local_img_s &src,short *color_ptr)
{
   mutex.lock();
   if (&src != this) src.mutex.lock();
   sp_mutex.unlock();

   bool result = img_3ub.mul_color(src.img_3ub,color_ptr);

   mutex.unlock();
   if (&src != this) src.mutex.unlock();
   sp_mutex.lock();

   return result;
}

#endif

