#ifndef _SYSTEMWIN32_H
#define _SYSTEMWIN32_H

#include <windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
#include <cstdlib>
#include <direct.h>
#include "str.h"
#include "file.h"
#include "str_tok.h"


namespace sys {

using namespace io_tools;
using namespace string_tools;
using namespace std;

class Task {
   HANDLE hRead;
   HANDLE hWrite;
   HANDLE hRead2;
   HANDLE hWrite2;
public:
   Task(HANDLE r1,
        HANDLE w1,
        HANDLE r2,
        HANDLE w2) {
      hRead = r1;
      hWrite = w1;
      hRead2 = r2;
      hWrite2 = w2;
   }
   ~Task() {
      CloseHandle(hRead);
      CloseHandle(hWrite);
      CloseHandle(hRead2);
      CloseHandle(hWrite2);
   }
   HANDLE get_read() { return hRead; }
   HANDLE get_write() { return hWrite; }
};

extern int System(const string & cmd);
extern Task* popen(const string & cmd);
extern int pgetc(HANDLE handle);
extern int pputc(HANDLE handle, int ch);
extern void pclose(Task* handle);

class shell_stream {
   Task* p_task;
   bool error;
public:
   shell_stream(const string & cmd) {
      p_task = popen(cmd);
      if(p_task == 0) {
         error = true;
      }
      else {
         error = false;
      }
   }
   ~shell_stream() {
      if(p_task) {
         delete p_task;
      }
   }
   HANDLE get_read() {
      HANDLE ret = 0;
      if(p_task) {
         ret = p_task->get_read();
      }
      return ret;
   }
   HANDLE get_write() {
      HANDLE ret = 0;
      if(p_task) {
         ret = p_task->get_write();
      }
      return ret;
   }
   shell_stream & operator<<(const string & str) {
      for(size_t i = 0; i < str.size(); i++) {
         *this << str[i];
      }
      return *this;
   }
   shell_stream & operator<<(const char ch) {
      if(pputc(p_task->get_write(), ch) == -1) {
         error = true;
      }
      return *this;
   }
   shell_stream & operator<<(const int val) {
      stringstream ss;
      ss << val;
      *this << ss.str();
   }
   shell_stream & operator<<(const float val) {
      stringstream ss;
      ss << val;
      *this << ss.str();
   }
   shell_stream & operator<<(const long val) {
      stringstream ss;
      ss << val;
      *this << ss.str();
   }
   shell_stream & operator<<(const double val) {
      stringstream ss;
      ss << val;
      *this << ss.str();
   }
   char get() {
      char ch = '\0';
      if((ch=pgetc(p_task->get_read())) == -1) {
         error = true;
      }
      return ch;
   }
   bool getline(string & str, const char end = '\n') {
      bool ret = true;
      str = "";
      int ch;
      ch = get();
      if(error) {
         ret = false;
      }
      else {
         while(ch != end) {
            str += (char)ch;
            ch = get();
            if(error) {
               ret = false;
               break;
            }
         }
      }
      return ret;
   }
   operator void*() const {
      return (void*)!error;
   }
};

}

#endif
