/*
 * File:   airports.h
 * Author: Filip Niksic, fniksic@gmail.com
 *
 * Created on 2008. veljaca 09, 08:39
 */

#ifndef AIRPORTS_H
#define	AIRPORTS_H

#include <vector>
#include <map>
#include <string>
#include <utility>
#include <stdexcept>
#include <iostream>
#include <cstddef>

#include "globals.h"
#include "wgs84.h"
#include "graph.h"

class Airports {
    Graph g;
    std::vector<std::string> codes;
    std::vector<WGS84::Coords> coords;
    std::map<std::string, Graph::Vertex_ID> codeMap;
public:
    void addAirport(const std::string& code, const WGS84::Coords &coord);
    void delAirport(const std::string& code);
    bool existsAirport(const std::string& code) const;
    void addFlight(const std::string& codeFrom, const std::string& codeTo);
    void delFlight(const std::string& codeFrom, const std::string& codeTo);
    bool existsFlight(const std::string& codeFrom, const std::string& codeTo) const;
    std::size_t loadAirports(std::istream&);
    std::size_t loadFlights(std::istream&);
    std::size_t setRandomFlights();
    std::size_t setAllFlights();
    std::size_t resetFlights();
    void printFlights(const std::string& codeFrom, const std::string& codeTo, std::ostream& = std::cout) const;
    void printShortest(const std::string& codeFrom, const std::string& codeTo, std::ostream& = std::cout) const;
    void printRoundtrip(const std::vector<std::string>& airports, std::ostream& = std::cout) const;
private:
    void checkAirport(const std::string& code) const;
    void addFlight(Graph::Vertex_ID from, Graph::Vertex_ID to);
    void delFlight(Graph::Vertex_ID from, Graph::Vertex_ID to);
    bool existsFlight(Graph::Vertex_ID from, Graph::Vertex_ID to) const;
};

inline void Airports::addFlight(Graph::Vertex_ID from, Graph::Vertex_ID to) {
    g.setEdge(from, to, WGS84::geodesic(coords[from], coords[to]) / 1000.0);
}

inline void Airports::delFlight(Graph::Vertex_ID from, Graph::Vertex_ID to) {
    g.resetEdge(from, to);
}

inline bool Airports::existsFlight(Graph::Vertex_ID from, Graph::Vertex_ID to) const {
    return g.existsEdge(from, to);
}

inline void Airports::checkAirport(const std::string& code) const {
    if (!existsAirport(code))
        throw std::runtime_error("Ne postoji aerodrom " + code);
}

inline void Airports::addAirport(const std::string& code, const WGS84::Coords &coord) {
    if (existsAirport(code))
        throw std::runtime_error("Aerodrom " + code + " vec postoji.");
    Graph::Vertex_ID v(g.addVertex());
    codes.push_back(code);
    coords.push_back(coord);
    codeMap.insert(std::make_pair(code, v));
}

inline void Airports::delAirport(const std::string& code) {
    checkAirport(code);
    std::map<std::string, Graph::Vertex_ID>::iterator it(codeMap.find(code));
    g.delVertex(it->second);
    codes.erase(codes.begin() + it->second);
    coords.erase(coords.begin() + it->second);
    codeMap.erase(it);
}

inline bool Airports::existsAirport(const std::string& code) const {
    return (codeMap.count(code) != 0);
}

inline void Airports::addFlight(const std::string& codeFrom, const std::string& codeTo) {
    checkAirport(codeFrom);
    checkAirport(codeTo);
    addFlight(codeMap[codeFrom], codeMap[codeTo]);
}

inline void Airports::delFlight(const std::string& codeFrom, const std::string& codeTo) {
    checkAirport(codeFrom);
    checkAirport(codeTo);
    delFlight(codeMap[codeFrom], codeMap[codeTo]);
}

inline bool Airports::existsFlight(const std::string& codeFrom, const std::string& codeTo) const {
    return existsAirport(codeFrom) && existsAirport(codeTo)
        && g.existsEdge(codeMap.find(codeFrom)->second, codeMap.find(codeTo)->second);
}

#endif	/* AIRPORTS_H */

