/*
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/*
  <file> UlsLog.h </file>
  <brief>
   This implements logging subsystem for UlsFactory Class.
  </brief>
  <author>
    Stanley Hong <link2next@gmail.com>, April 2017.
  </author>
*/
#pragma once

#include "UlsObject.h"
#include <stdio.h>

namespace uls {
	namespace polaris {
#define ULS_EXCLUDE_HFILES
#include "uls/uls_config.h"
#undef ULS_EXCLUDE_HFILES
		public ref class uls_xport_t {
		public:
			delegate void delegate_uls_putstr_t(Object ^xdat, const char *line, int len);

		private:
			delegate_uls_putstr_t ^putstr;
			Object ^xdat;

		public:
			uls_xport_t(delegate_uls_putstr_t ^puts);
			virtual ~uls_xport_t();
			void setXdat(Object ^udat);
			Object ^getXdat();
			void putStr(const char *line, int len);
		};

		public ref class UlsLog : UlsObject {
			//
			// sysprn
			//
			bool sysprn_opened;
			bool isFinalized, isDisposed;
			FILE *fp_sysprn;

			//
			// syslog
			//
			FILE *fp_syslog;

			// <brief>
			//
			// </brief>
			static UlsObjectListExp ^objs_list;

			void __put_str_fillchars(uls_xport_t ^xport, int n, char ch);
			const char* __check_line_perc(uls_xport_t ^xport, const char *line, int *ptr_len);

			static UlsLog()
			{
				objs_list = gcnew UlsObjectListExp();
			}

			static void err_exit(void);

		protected:
			ref struct uls_xport_str_t {
				int buflen, bufsiz;
				char *buf;
			};

			ref struct uls_xport_fp_t {
				FILE *fp;
			};

			void ulslog_lock_null(void);
			void ulslog_unlock_null(void);

			int uls_num2str(char *numstr, unsigned int num, int base_shift);
			void __put_str_width(uls_xport_t ^xport, const char *line, int len, int width, char padding_ch);
			int __format_strseg(uls_xport_t ^xport, const char **ptr_fmt, const void *udat);

			void __put_str_strbuf(Object ^xdat, const char *line, int len);
			void __put_str_file(Object ^xdat, const char *line, int len);

			uls_xport_t^ get_xport_strbuf(char *buf, int bufsiz);
			uls_xport_t^ get_xport_filebuf(FILE *fp);

			void uls_initialize_sysprn(void);
			void uls_finalize_sysprn(void);

			void uls_initialize_syserr(FILE *fp);
			void uls_finalize_syserr(void);

		public:
			delegate void _delegate_ulslog_lock(void);
			typedef _delegate_ulslog_lock ^ulslog_lock_proc_t;

			ulslog_lock_proc_t ulslog_lock_syserr;
			ulslog_lock_proc_t ulslog_unlock_syserr;

			ulslog_lock_proc_t ulslog_lock_sysprn;
			ulslog_lock_proc_t ulslog_unlock_sysprn;

			UlsLog(ulslog_lock_proc_t lock, ulslog_lock_proc_t unlock);
			virtual ~UlsLog();
			virtual void finalizer() override;
			!UlsLog();

			void ulslog_reset_lock_syserr(ulslog_lock_proc_t lock, ulslog_lock_proc_t unlock);
			void ulslog_reset_lock_sysprn(ulslog_lock_proc_t lock, ulslog_lock_proc_t unlock);

			//
			// snprintf
			//
			int uls_snprintf(char *buf, int bufsiz, const char *fmt);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, int d1);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1, const char *s2);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, int d1, int d2);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1, int d2);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, int d1, const char *s2);

			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1, const char *s2, const char *s3);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1, int d2, int d3);
			int uls_snprintf(char *buf, int bufsiz, const char *fmt, const char *s1, int d2, const char *s3);

			//
			// fprintf
			//
			int uls_fprintf(FILE *fp, const char *fmt);
			int uls_fprintf(FILE *fp, const char *fmt, const char *s1);
			int uls_fprintf(FILE *fp, const char *fmt, int d1);
			int uls_fprintf(FILE *fp, const char *fmt, const char *s1, const char *s2);
			int uls_fprintf(FILE *fp, const char *fmt, int d1, int d2);
			int uls_fprintf(FILE *fp, const char *fmt, const char *s1, int d2);
			int uls_fprintf(FILE *fp, const char *fmt, int d1, const char *s2);

			int uls_fprintf(FILE *fp, const char *fmt, const char *s1, const char *s2, const char *s3);
			int uls_fprintf(FILE *fp, const char *fmt, int d1, int d2, int d3);
			int uls_fprintf(FILE *fp, const char *fmt, int d1, const char *s2, const char *s3);
			int uls_fprintf(FILE *fp, const char *fmt, const char *s1, const char *s2, int d3);

			//
			// printf
			//
			void uls_printf(const char *fmt);
			void uls_printf(const char *fmt, const char *s1);
			void uls_printf(const char *fmt, int d1);
			void uls_printf(const char *fmt, const char *s1, const char *s2);
			void uls_printf(const char *fmt, int d1, int d2);
			void uls_printf(const char *fmt, const char *s1, int d2);
			void uls_printf(const char *fmt, int d1, const char *s2);

			void uls_printf(const char *fmt, const char *s1, const char *s2, const char *s3);
			void uls_printf(const char *fmt, int d1, int d2, int d3);
			void uls_printf(const char *fmt, int d1, const char *s2, const char *s3);
			void uls_printf(const char *fmt, const char *s1, const char *s2, int d3);

			//
			// sysprn
			//
			int uls_sysprn_open(FILE* fp, void *unused);
			void uls_sysprn_close(void);
			int uls_sysprn(const char *fmt);
			int uls_sysprn(const char *fmt, const char *s1);
			int uls_sysprn(const char *fmt, int d1);
			int uls_sysprn(const char *fmt, const char *s1, const char *s2);
			int uls_sysprn(const char *fmt, int d1, int d2);
			int uls_sysprn(const char *fmt, const char *s1, int d2);
			int uls_sysprn(const char *fmt, int d1, const char *s2);
			int uls_sysprn(const char *fmt, const char *s1, const char *s2, const char *s3);
			int uls_sysprn(const char *fmt, const char *s1, const char *s2, int d3);
			void uls_sysprn_puttabs(int n);

			//
			// log
			//
			static void err_log_static(const char *fmt);
			static void err_panic_static(const char *fmt);

			void err_log(const char *fmt);
			void err_log(const char *fmt, const char *s1);
			void err_log(const char *fmt, int d1);
			void err_log(const char *fmt, const char *s1, const char *s2);
			void err_log(const char *fmt, int d1, int d2);
			void err_log(const char *fmt, const char *s1, int d2);
			void err_log(const char *fmt, int d1, const char *s2);

			void err_panic(const char *fmt);
			void err_panic(const char *fmt, const char *s1);
			void err_panic(const char *fmt, int d1);
			void err_panic(const char *fmt, const char *s1, const char *s2);
			void err_panic(const char *fmt, int d1, int d2);
			void err_panic(const char *fmt, const char *s1, int d2);
			void err_panic(const char *fmt, int d1, const char *s2);

			static void releaseUlsObjectList()
			{
				UlsObject::finalizeUlsObjectList(objs_list);
				objs_list = nullptr;
			}
		};
	} //  End of polaris
} // End of uls
