/*! @file

    @id $Id$
    */
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#ifndef PROXY_WINDOZE_HXX
#define PROXY_WINDOZE_HXX

#ifdef DATADIR
#undef DATADIR
#endif
#include <windows.h>
#include <winhttp.h>

#include <iostream> // debug

namespace proxy {

  class Windoze: public Interface {

    public:

      Windoze() {}

      virtual ~Windoze() {}

      //! Implemented using M$ WinHTTP
      virtual List proxies(const std::string& url) {

        List res;

        WINHTTP_PROXY_INFO proxyInfo;
        ZeroMemory(&proxyInfo, sizeof(proxyInfo));
        HINTERNET hHttpSession(WinHttpOpen(L"WinHTTP AutoProxy/1.0",
                                           WINHTTP_ACCESS_TYPE_NO_PROXY,
                                           WINHTTP_NO_PROXY_NAME,
                                           WINHTTP_NO_PROXY_BYPASS,
                                           0));
        try {
          if (!hHttpSession) throw exc::error();
        
          WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
          ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
          AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
          AutoProxyOptions.dwAutoDetectFlags =
            WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
          AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
          
          if (!WinHttpGetProxyForUrl(hHttpSession,
                                     std::wstring(url.begin(),
                                                  url.end()).data(),
                                     &AutoProxyOptions, &proxyInfo))
            throw exc::error();
          
          std::wstring list(proxyInfo.lpszProxy);
          std::wcout<<"LIST=\""<<list<<"\""<<std::endl;
          for (std::wstring::size_type oldpos(0), pos(0);
               (pos=list.find(L";", oldpos)), oldpos!=std::wstring::npos;
               oldpos=(pos!=std::wstring::npos?pos+1:pos)) {
            std::wstring proxy(list.substr(oldpos, pos-oldpos));
            std::wstring port((oldpos=proxy.rfind(L":"))!=std::wstring::npos
                              ?proxy.substr(oldpos+1):std::wstring());
            std::wstring host(proxy.substr(0, proxy.rfind(L":")));
            Type type(DIRECT);
            switch (proxyInfo.dwAccessType) { //! @todo use or remove
              case WINHTTP_ACCESS_TYPE_NO_PROXY: type=DIRECT; break;
              case WINHTTP_ACCESS_TYPE_DEFAULT_PROXY: type=DEFAULT; break;
              case WINHTTP_ACCESS_TYPE_NAMED_PROXY: type=HTTP; break;
            }
            if (host.size()>0)
              res.push_back(Proxy(type,
                                  std::string(host.begin(), host.end()),
                                  std::string(port.begin(), port.end())));
          }
          if (!res.size()) res.push_back(Proxy());
          
          if (proxyInfo.lpszProxy) GlobalFree(proxyInfo.lpszProxy);
          if (proxyInfo.lpszProxyBypass) GlobalFree(proxyInfo.lpszProxyBypass);
          if (hHttpSession) WinHttpCloseHandle(hHttpSession);
        } catch (...) {
          if (proxyInfo.lpszProxy) GlobalFree(proxyInfo.lpszProxy);
          if (proxyInfo.lpszProxyBypass) GlobalFree(proxyInfo.lpszProxyBypass);
          if (hHttpSession) WinHttpCloseHandle(hHttpSession);
          if (!res.size()) res.push_back(Proxy()); // try direct acces
        }
        
        return res;
      }
  };
}

#endif
