// This file is part of the xmule project.
// This file contains debug specific implementation.
//
// Copyright (c) 2003 - 2004, by
//
// Carlo Wood, Run on IRC <carlo@alinoe.com>
// RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
// Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifdef PRECOMP
#include "pch.h"
#endif

#ifdef CWDEBUG

#include "sys.h"                  // Needed for platform-specific code
#include <pthread.h>              // Needed for pthread_mutex_t;
#include <cctype>                 // Needed for std::isprint
#include <iomanip>                // Needed for setfill

#include "Debug.h"                // Interface declarations

// This lock is only used for libcwd so far, so put this here.
extern pthread_mutex_t cout_mutex;

namespace debug
{
    namespace channels // namespace DEBUGCHANNELS
    {
        namespace dc
        {
            // Add new debug channels here.
            channel_ct dirtree("DIRTREE");
            channel_ct sockets("SOCKETS");
            channel_ct packet("PACKET");
            channel_ct sockio("SOCKIO");
        } // namespace dc
    } // namespace DEBUGCHANNELS

    // Initialize debugging code from new threads.
    void init_thread()
    {
        // Everything below needs to be repeated at the start of a new
        // thread because every thread starts in a completely reset
	// state, with all debug channels off etc.

        // Turn on all debug channels by default.
        ForAllDebugChannels( while (!debugChannel.is_on()) debugChannel.on() );
        // Turn off specific debug channels.
        Debug( dc::bfd.off() ); 
        Debug( dc::malloc.off() ); 

        // Turn on debug output.
        Debug( libcw_do.on() );
        Debug( libcw_do.set_ostream(&std::cout, &cout_mutex) );

        static bool first_thread = true;
        if (!first_thread)            // So far, xMule has only one thread.  So don't add a thread id.
        {
            // Set the thread id in the margin.
            char margin[12];
            sprintf(margin, "%-10lu ", pthread_self());
            Debug( libcw_do.margin().assign(margin, 11) );
        }
        
        // Write a list of all existing debug channels to the default debug device.
        Debug( list_channels_on(libcw_do) );
    }

    // Initialize debugging code from main().
    void init()
    {
        // You want this, unless you mix streams output with C output.
        // Read  http://gcc.gnu.org/onlinedocs/libstdc++/27_io/howto.html#8 for an explanation.
        // We can't use it, because other code uses printf to write to the console.
        //std::ios::sync_with_stdio(false);

        // This will warn you when you are using header files that do not belong to the
        // shared libcwd object that you linked with.
        Debug( check_configuration() );
#if CWDEBUG_ALLOC
        // Remove all current (pre- main) allocations from the Allocated Memory Overview.
        libcw::debug::make_all_allocations_invisible_except(NULL);
#endif
        init_thread();
        Debug( read_rcfile() );
    }

    void DumpBufferHex(libcw::debug::channel_ct const& channel, unsigned char const* buf, size_t size)
    {
        for (size_t addr = 0; addr < size; addr += 16)
        {
            LibcwDoutScopeBegin(DEBUGCHANNELS, libcw::debug::libcw_do, channel)
            LibcwDoutStream << std::hex << std::setfill('0') << std::setw(4) << addr << " |";
            int offset;
            for (offset = 0; offset < 16 && addr + offset < size; ++offset)
            {
                LibcwDoutStream << ' ' << std::hex << std::setfill('0') << std::setw(2) << (int)buf[addr + offset];
            }
            for (; offset < 16; ++offset)
            {
                LibcwDoutStream << "   ";
            }
            LibcwDoutStream << " | ";
            for (int offset = 0; offset < 16 && addr + offset < size; ++offset)
            {
                unsigned char c = buf[addr + offset];
                if (!std::isprint(c))
                {
                    c = '.';
                }
                LibcwDoutStream << c;
            }
            LibcwDoutScopeEnd;
        }
    }
} // namespace debug

#endif // CWDEBUG
