// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2011 XORP, Inc and Others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2, June
// 1991 as published by the Free Software Foundation. Redistribution
// and/or modification of this program under the terms of any other
// version of the GNU General Public License is not permitted.
// 
// 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. For more details,
// see the GNU General Public License, Version 2, a copy of which can be
// found in the XORP LICENSE.gpl file.
// 
// XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net


#ifndef __PIM_PIM_MRE_TASK_HH__
#define __PIM_PIM_MRE_TASK_HH__


//
// PIM Multicast Routing Entry task definitions.
//




#include "libxorp/time_slice.hh"
#include "pim_mre.hh"
#include "pim_mre_track_state.hh"


//
// Constants definitions
//


//
// Structures/classes, typedefs and macros
//

class PimMrt;

// Task for PIM-specific Multicast Routing Entry
class PimMreTask {
public:
    PimMreTask(PimMrt* pim_mrt, PimMreTrackState::input_state_t input_state);
    ~PimMreTask();
    
    // General info: PimNode, PimMrt, family, etc.
    PimNode*	pim_node()	const;
    PimMrt*	pim_mrt()	const	{ return _pim_mrt;		}
    int		family()	const;
    
    bool	run_task();
    bool	run_task_rp();
    bool	run_task_wc();
    bool	run_task_sg_sg_rpt();
    bool	run_task_mfc();
    void	perform_pim_mre_actions(PimMre *pim_mre);
    void	perform_pim_mre_sg_sg_rpt_actions(PimMre *pim_mre_sg,
						  PimMre *pim_mre_sg_rpt);
    void	perform_pim_mfc_actions(PimMfc *pim_mfc);
    void	perform_pim_mfc_actions(const IPvX& source_addr,
					const IPvX& group_addr);
    void	add_pim_mre(PimMre *pim_mre);
    void	add_pim_mre_delete(PimMre *pim_mre);
    void	add_pim_mfc(PimMfc *pim_mfc);
    void	add_pim_mfc_delete(PimMfc *pim_mfc);
    void	add_mrib_delete_list(const list<Mrib *>& mrib_list);
    
    //
    // (*,*,RP) state setup
    //
    void	set_rp_addr_rp(const IPvX& rp_addr) {
	_rp_addr_rp = rp_addr;
	_is_set_rp_addr_rp = true;
    }
    void	set_rp_addr_prefix_rp(const IPvXNet& rp_addr_prefix) {
	_rp_addr_prefix_rp = rp_addr_prefix;
	_is_set_rp_addr_prefix_rp = true;
    }
    
    //
    // (*,G) state setup
    //
    void	set_group_addr_wc(const IPvX& group_addr) {
	_group_addr_wc = group_addr;
	_is_set_group_addr_wc = true;
    }
    void	set_rp_addr_wc(const IPvX& rp_addr) {
	_rp_addr_wc = rp_addr;
	_is_set_rp_addr_wc = true;
    }
    void	set_group_addr_prefix_wc(const IPvXNet& group_addr_prefix) {
	_group_addr_prefix_wc = group_addr_prefix;
	_is_set_group_addr_prefix_wc = true;
    }
    
    //
    // (S,G) and (S,G,rpt) state setup
    //
    void	set_source_addr_sg_sg_rpt(const IPvX& source_addr) {
	_source_addr_sg_sg_rpt = source_addr;
	_is_set_source_addr_sg_sg_rpt = true;
    }
    void	set_group_addr_sg_sg_rpt(const IPvX& group_addr) {
	_group_addr_sg_sg_rpt = group_addr;
	_is_set_group_addr_sg_sg_rpt = true;
    }
    void	set_source_addr_prefix_sg_sg_rpt(const IPvXNet& addr_prefix) {
	_source_addr_prefix_sg_sg_rpt = addr_prefix;
	_is_set_source_addr_prefix_sg_sg_rpt = true;
    }
    void	set_rp_addr_sg_sg_rpt(const IPvX& rp_addr) {
	_rp_addr_sg_sg_rpt = rp_addr;
	_is_set_rp_addr_sg_sg_rpt = true;
    }
    
    //
    // PimMfc state setup
    //
    void	set_source_addr_mfc(const IPvX& source_addr) {
	_source_addr_mfc = source_addr;
	_is_set_source_addr_mfc = true;
    }
    void	set_group_addr_mfc(const IPvX& group_addr) {
	_group_addr_mfc = group_addr;
	_is_set_group_addr_mfc = true;
    }
    void	set_source_addr_prefix_mfc(const IPvXNet& addr_prefix) {
	_source_addr_prefix_mfc = addr_prefix;
	_is_set_source_addr_prefix_mfc = true;
    }
    void	set_rp_addr_mfc(const IPvX& rp_addr) {
	_rp_addr_mfc = rp_addr;
	_is_set_rp_addr_mfc = true;
    }
    
    //
    // Other related setup
    //
    void	set_pim_nbr_addr_rp(const IPvX& v) {
	_pim_nbr_addr = v;
	_is_set_pim_nbr_addr_rp = true;
    }
    void	set_pim_nbr_addr_wc(const IPvX& v) {
	_pim_nbr_addr = v;
	_is_set_pim_nbr_addr_wc = true;
    }
    void	set_pim_nbr_addr_sg_sg_rpt(const IPvX& v) {
	_pim_nbr_addr = v;
	_is_set_pim_nbr_addr_sg_sg_rpt = true;
    }
    void	set_vif_index(uint32_t v) { _vif_index = v; }
    void	set_addr_arg(const IPvX& v) { _addr_arg = v; }
    
    //
    // Misc. information
    //
    uint32_t	vif_index() const { return (_vif_index); }
    const IPvX&	addr_arg() const { return (_addr_arg); }
    PimMreTrackState::input_state_t input_state() const { return (_input_state); }
    
private:
    // Private state
    PimMrt* _pim_mrt;		// The PIM MRT
    
    list<PimMreAction>	_action_list_rp; // The list of (*,*,RP) actions
    list<PimMreAction>	_action_list_wc; // The list of (*,G) actions
    list<PimMreAction>	_action_list_sg_sg_rpt; // The list of (S,G) and
						// (S,G,rpt) actions
    list<PimMreAction>	_action_list_mfc; // The list of MFC actions
    
    TimeSlice		_time_slice;	// The time slice
    
    const PimMreTrackState::input_state_t _input_state;	// The input state
    
    //
    // (*,*,RP) related state
    //
    bool	_is_set_rp_addr_rp;
    IPvX	_rp_addr_rp;
    bool	_is_set_rp_addr_prefix_rp;
    IPvXNet	_rp_addr_prefix_rp;
    list<PimMre *> _pim_mre_rp_list;		// (*,*,RP) entries to process
    list<PimMre *> _pim_mre_rp_processed_list;	// (*,*,RP) processed entries
    list<PimMre *> _pim_mre_rp_delete_list;	// (*,*,RP) entries to delete
    // State to continue the processing with the next time slice
    bool	_is_processing_rp;
    bool	_is_processing_rp_addr_rp;
    IPvX	_processing_rp_addr_rp;
    
    //
    // (*,G) related state
    //
    bool	_is_set_group_addr_wc;
    IPvX	_group_addr_wc;
    bool	_is_set_rp_addr_wc;
    IPvX	_rp_addr_wc;
    bool	_is_set_group_addr_prefix_wc;
    IPvXNet	_group_addr_prefix_wc;
    list<PimMre *> _pim_mre_wc_list;		// (*,G) entries to process
    list<PimMre *> _pim_mre_wc_processed_list;	// (*,G) processed entries
    list<PimMre *> _pim_mre_wc_delete_list;	// (*,G) entries to delete
    // State to continue the processing with the next time slice
    bool	_is_processing_wc;
    bool	_is_processing_rp_addr_wc;
    IPvX	_processing_rp_addr_wc;
    bool	_is_processing_group_addr_wc;
    IPvX	_processing_group_addr_wc;
    
    //
    // (S,G) and (S,G,rpt) related state
    //
    bool	_is_set_source_addr_sg_sg_rpt;
    IPvX	_source_addr_sg_sg_rpt;
    bool	_is_set_group_addr_sg_sg_rpt;
    IPvX	_group_addr_sg_sg_rpt;
    bool	_is_set_source_addr_prefix_sg_sg_rpt;
    IPvXNet	_source_addr_prefix_sg_sg_rpt;
    bool	_is_set_rp_addr_sg_sg_rpt;
    IPvX	_rp_addr_sg_sg_rpt;
    list<PimMre *> _pim_mre_sg_list;		// (S,G) entries to process
    list<PimMre *> _pim_mre_sg_processed_list;	// (S,G) processed entries
    list<PimMre *> _pim_mre_sg_delete_list;	// (S,G) entries to delete
    list<PimMre *> _pim_mre_sg_rpt_list;	// (S,G,rpt) entries to process
    list<PimMre *> _pim_mre_sg_rpt_processed_list;// (S,G,rpt) processed entries
    list<PimMre *> _pim_mre_sg_rpt_delete_list;	// (S,G,rpt) entries to delete
    // State to continue the processing with the next time slice
    bool	_is_processing_sg_sg_rpt;
    bool	_is_processing_sg_source_addr_sg_sg_rpt;
    IPvX	_processing_sg_source_addr_sg_sg_rpt;
    bool	_is_processing_sg_rpt_source_addr_sg_sg_rpt;
    IPvX	_processing_sg_rpt_source_addr_sg_sg_rpt;
    bool	_is_processing_sg_group_addr_sg_sg_rpt;
    IPvX	_processing_sg_group_addr_sg_sg_rpt;
    bool	_is_processing_sg_rpt_group_addr_sg_sg_rpt;
    IPvX	_processing_sg_rpt_group_addr_sg_sg_rpt;
    bool	_is_processing_rp_addr_sg;
    bool	_is_processing_rp_addr_sg_rpt;
    IPvX	_processing_rp_addr_sg_sg_rpt;
    
    //
    // PimMfc related state
    //
    bool	_is_set_source_addr_mfc;
    IPvX	_source_addr_mfc;
    bool	_is_set_group_addr_mfc;
    IPvX	_group_addr_mfc;
    bool	_is_set_source_addr_prefix_mfc;
    IPvXNet	_source_addr_prefix_mfc;
    bool	_is_set_rp_addr_mfc;
    IPvX	_rp_addr_mfc;
    list<PimMfc *> _pim_mfc_list;		// PimMfc entries to process
    list<PimMfc *> _pim_mfc_processed_list;	// PimMfc processed entries
    list<PimMfc *> _pim_mfc_delete_list;	// PimMfc entries to delete
    // State to continue the processing with the next time slice
    bool	_is_processing_mfc;
    bool	_is_processing_source_addr_mfc;
    IPvX	_processing_source_addr_mfc;
    bool	_is_processing_group_addr_mfc;
    IPvX	_processing_group_addr_mfc;
    bool	_is_processing_rp_addr_mfc;
    IPvX	_processing_rp_addr_mfc;
    
    //
    // (*,*,RP), (*,G), (S,G), (S,G,rpt) PimNbr related state
    //
    bool	_is_set_pim_nbr_addr_rp;
    bool	_is_set_pim_nbr_addr_wc;
    bool	_is_set_pim_nbr_addr_sg_sg_rpt;
    IPvX	_pim_nbr_addr;
    bool	_is_processing_pim_nbr_addr_rp;
    bool	_is_processing_pim_nbr_addr_wc;
    bool	_is_processing_pim_nbr_addr_sg;
    bool	_is_processing_pim_nbr_addr_sg_rpt;
    
    // The 'occasionally-used' argument(s).
    uint32_t	_vif_index;
    IPvX	_addr_arg;

    //
    // Mrib related state
    //
    list<Mrib *> _mrib_delete_list;
};

#endif // __PIM_PIM_MRE_TASK_HH__
