/*
 * © Copyright 1996-2012 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

// File ObsKey.h
// Manuel Fuentes - ECMWF Oct 96

#ifndef ObsKey_H
#define ObsKey_H

#include <memory.h>
#include "fortint.h"


#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std;

typedef struct {
#ifdef LITTLE_END
    unsigned char type;
    unsigned char subtype;
    unsigned char date_time[5];
    unsigned char spare02[25];
#else
    unsigned int type : 8;    /* 8   bits =  1  bytes   */
    unsigned int subtype : 8; /* 16  bits =  2  bytes   */
    unsigned int year : 12;   /* 28                     */
    unsigned int month : 4;   /* 32  bits =  4  bytes   */
    unsigned int day : 6;     /* 38                     */
    unsigned int hour : 5;    /* 43                     */
    unsigned int minute : 6;  /* 49                     */
    unsigned int second : 6;  /* 55                     */
    unsigned int spare01 : 1; /* 56  bits =  7   bytes  */
    char spare02[25];         /* 256 bits = 32   bytes  */
#endif
} keyheader;

typedef unsigned char timec[3];
typedef unsigned char correction;


typedef struct {

#ifdef LITTLE_END
    keyheader header;
    unsigned char length[2];
    timec rdbtime;
    timec rectime;
    correction corr1;
    correction corr2;
    correction corr3;
    correction corr4;
    unsigned char qc;
    unsigned char spare09[3];
#else
    keyheader header;
    unsigned int length : 16;
    timec rdbtime;
    timec rectime;
    correction corr1;
    correction corr2;
    correction corr3;
    correction corr4;
    unsigned int qc : 8;
    unsigned int spare09 : 24; /* 48 bytes */
#endif

} key; /* 48 bytes */

typedef long Ordinal;

// Forward declarations

class BadBufr {

public:
    BadBufr(const string& s) :
        s_(s) {}
    const string& text() { return s_; }

private:
    string s_;
};

class ObsKey {
public:
    // -- Exceptions
    // None

    // -- Contructors

    ObsKey() {}
    ObsKey(char*, fortint, bool = true);

    // -- Destructor
    ~ObsKey() {}

    // -- Operators

    bool operator<(const ObsKey& other) const {
        return ::memcmp(&key_, &other.key_, sizeof(keyheader)) < 0;
        ;
    }
    bool operator==(const ObsKey& other) const {
        return ::memcmp(&key_, &other.key_, sizeof(keyheader)) == 0;
        ;
    }

    // -- Methods

    Ordinal length() const;
    Ordinal type() const { return key_.header.type; }
    Ordinal subtype() const { return key_.header.subtype; }

    double latitude() const;
    double longitude() const;

    int year() const;
    int month() const;
    int day() const;
    int hour() const;
    int minute() const;
    int second() const;
    long station() const;

    void print(ostream&) const;  // Change to virtual if base class


private:
    // -- Members

    key key_;
    Ordinal length_;

    // -- Overridden methods
    // None

    // -- Class members
    // None

    // -- Class methods
    // None

    // -- Friends

    friend ostream& operator<<(ostream& s, const ObsKey& p) {
        p.print(s);
        return s;
    }
};

#endif
