use winnow::ModalResult as PResult;
use winnow::combinator::{alt, cut_err};
use winnow::prelude::*;
use crate::lexer::Token;
use crate::parser::{ParsedField, Stream, parse_u8, parse_u16, parse_u32, tag};
pub(crate) mod ah;
pub(crate) mod bfd;
pub(crate) mod bgp;
pub(crate) mod esp;
pub(crate) mod geneve;
pub(crate) mod gre;
pub(crate) mod hsrp;
pub(crate) mod icmp;
pub(crate) mod igmp;
pub(crate) mod ikev2;
pub(crate) mod ipsec;
pub(crate) mod mld;
pub(crate) mod ndp;
pub(crate) mod openflow;
pub(crate) mod ospf;
pub(crate) mod pim;
pub(crate) mod rip;
pub(crate) mod vrrp;
pub(crate) mod vxlan;
pub(crate) mod wireguard;
pub(crate) use ah::*;
pub(crate) use bfd::*;
pub(crate) use bgp::*;
pub(crate) use esp::*;
pub(crate) use geneve::*;
pub(crate) use gre::*;
pub(crate) use hsrp::*;
pub(crate) use icmp::*;
pub(crate) use igmp::*;
pub(crate) use ikev2::*;
pub(crate) use ipsec::*;
pub(crate) use mld::*;
pub(crate) use ndp::*;
pub(crate) use openflow::*;
pub(crate) use ospf::*;
pub(crate) use pim::*;
pub(crate) use rip::*;
pub(crate) use vrrp::*;
pub(crate) use vxlan::*;
pub(crate) use wireguard::*;
pub(crate) fn parse_l3_field<'i, 'a>(input: &mut Stream<'i, 'a>) -> PResult<ParsedField<'a>> {
alt((
alt((
parse_icmp_field,
parse_ndp_field,
parse_igmp_field,
parse_mld_field,
parse_gre_field,
parse_vxlan_field,
parse_geneve_field,
parse_ipsec_field,
)),
alt((
parse_esp_field,
parse_ah_field,
parse_ikev2_field,
parse_wireguard_field,
parse_ospf_field,
parse_bgp_field,
parse_rip_field,
parse_vrrp_field,
)),
alt((
parse_hsrp_field,
parse_pim_field,
parse_bfd_field,
parse_openflow_field,
)),
alt((
(tag(Token::Dscp), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Dscp(v, (s.start, s.end - s.start))),
(tag(Token::Ecn), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Ecn(v, (s.start, s.end - s.start))),
(tag(Token::Ttl), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Ttl(v, (s.start, s.end - s.start))),
(tag(Token::FlowLabel), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::FlowLabel(v, (s.start, s.end - s.start))),
(tag(Token::IpId), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::IpId(v, (s.start, s.end - s.start))),
tag(Token::Df).map(|(_, s)| ParsedField::Df((s.start, s.len()))),
tag(Token::Mf).map(|(_, s)| ParsedField::Mf((s.start, s.len()))),
(tag(Token::FragOffset), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::FragOffset(v, (s.start, s.end - s.start))),
)),
(tag(Token::NextHeader), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::NextHeader(v, (s.start, s.end - s.start))),
))
.parse_next(input)
}