/***************************************************************************
 *
 * messages.cpp
 *
 * $Id: messages.cpp 448754 2006-09-22 00:42:16Z sebor $
 *
 ***************************************************************************
 *
 * Licensed to the Apache Software  Foundation (ASF) under one or more
 * contributor  license agreements.  See  the NOTICE  file distributed
 * with  this  work  for  additional information  regarding  copyright
 * ownership.   The ASF  licenses this  file to  you under  the Apache
 * License, Version  2.0 (the  "License"); you may  not use  this file
 * except in  compliance with the License.   You may obtain  a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the  License is distributed on an  "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
 * implied.   See  the License  for  the  specific language  governing
 * permissions and limitations under the License.
 *
 * Copyright 2001-2006 Rogue Wave Software.
 * 
 **************************************************************************/

#include "def.h"          // for Def
#include "diagnostic.h"   // for issue_diag()
#include "path.h"         // for get_pathname()
#include "scanner.h"      // for scanner

#include <cassert>        // for assert()
#include <fstream>        // for ofstream


static const char lc_name[] = "LC_MESSAGES";


void Def::process_messages()
{
    issue_diag (I_STAGE, false, 0, "processing %s section\n", lc_name);

    // nesting level
    int nesting_level = 0;

    messages_def_found_ = true;

    std::string name;

    while ((next = scanner_.next_token()).token != Scanner::tok_messages) {

        switch(next.token) {

        case Scanner::tok_end:
            next = scanner_.next_token();
            if (next.token == Scanner::tok_messages) {
                // end of numeric block
                if (nesting_level == 0) 
                    return;

                nesting_level--;
                scanner_.close ();
            } else
                issue_diag (E_SYNTAX, true, &next,
                            "wrong section name in END directive\n");

            break;

        case Scanner::tok_copy: {
            next = scanner_.next_token();
            if (next.token != Scanner::tok_string)
                issue_diag (E_SYNTAX, true, &next,
                            "expected string following \"copy\" directive\n");

            // bump up the nesting level
            nesting_level++;

            issue_diag (I_STAGE, false, 0, "processing copy directive\n");

            // open the file
            scanner_.open (get_pathname (strip_quotes (next.name), next.file));

            // get comment char and escape char; 
            // these informations are stored by the scanner
            while ((next = scanner_.next_token ()).token 
                   != Scanner::tok_messages ){
                // the LC_IDENTIFICATION section may also have a 
                // LC_MESSAGES token that will mess up the parsing
                if (next.token == Scanner::tok_ident) {
                    while ((next = scanner_.next_token()).token
                           != Scanner::tok_end );
                    next = scanner_.next_token();
                }
            }
            break;
        }

        case Scanner::tok_yesexpr: {
            next = scanner_.next_token();
            messages_st_.yesexpr = convert_string (next.name);
            messages_st_.wyesexpr = convert_wstring (next);
            break;
        }

        case Scanner::tok_noexpr: {
            next = scanner_.next_token();
            messages_st_.noexpr = convert_string (next.name);
            messages_st_.wnoexpr = convert_wstring (next);
            break;
        }

        default:
            break;
        }
    }
}


void Def::write_messages(std::string dir_name)
{
    assert (!dir_name.empty());
    
    if (messages_written_)
        return;

    if (!messages_def_found_) {
        issue_diag (I_SKIP, false, 0,
                    "%s section not found, skipping\n", lc_name);
        return;
    }

    (dir_name += _RWSTD_PATH_SEP) += lc_name;

    issue_diag (I_OPENWR, false, 0, "writing %s\n", dir_name.c_str ());

    std::ofstream out (dir_name.c_str(), std::ios::binary);
    out.exceptions (std::ios::failbit | std::ios::badbit);

    // now calculate the offsets for the wide string representations
    messages_out_.yesexpr_off[1] = 0;
    messages_out_.noexpr_off[1] = messages_out_.yesexpr_off[1] 
        + (messages_st_.wyesexpr.size() + 1) * sizeof (wchar_t) ;
        
    // now calculate the offsets for the narrow string representations
    messages_out_.yesexpr_off[0] = messages_out_.noexpr_off[1] 
        + (messages_st_.wnoexpr.size() + 1) * sizeof (wchar_t);
    messages_out_.noexpr_off[0] = messages_out_.yesexpr_off[0] 
        + (messages_st_.yesexpr.size() + 1) * sizeof (char);

    messages_out_.codeset_off = messages_out_.noexpr_off[0] 
        + (messages_st_.noexpr.size() + 1) * sizeof (char);
    messages_out_.charmap_off = messages_out_.codeset_off 
        + (charmap_.get_code_set_name().size() + 1) * sizeof (char);

    // first write out the messages structure
    out.write ((char*)&messages_out_, sizeof(messages_out_));

    // now write out all the strings
    out.write ((const char*)messages_st_.wyesexpr.c_str(), 
               (messages_st_.wyesexpr.size() + 1) * sizeof (wchar_t));
    out.write ((const char*)messages_st_.wnoexpr.c_str(), 
               (messages_st_.wnoexpr.size() + 1) * sizeof (wchar_t));

    out << messages_st_.yesexpr << std::ends;
    out << messages_st_.noexpr << std::ends;
    out << charmap_.get_code_set_name() << std::ends;
    out << charmap_.get_charmap_name() << std::ends;
    out.close();
}
