# Three letters (for PDB)
# =======================

# download("ftp://ftp.wwpdb.org/pub/pdb/data/monomers/components.cif","components.cif")
#
# open("components.cif","r") do fh
#     m3 = nothing
#     m1 = nothing
#     peptide = false
#     for line in eachline(fh)
#         if startswith(line, "_chem_comp")
#             if m3 == nothing
#                 m3 = match(r"^_chem_comp.three_letter_code\s+(\w{3})\s*$",line) # It avoids: DA, DT, ...
#             end
#             if m1 == nothing
#                 m1 = match(r"^_chem_comp.one_letter_code\s+(\w{1})\s*$",line) # It avoids: ?
#             end
#             if startswith(line,"_chem_comp.type")
#                 peptide = occursin(r"peptide"i,line) # It avoids 0DA, 2DA, etc...
#             end
#             if m1 != nothing && m3 != nothing && parent != nothing && peptide
#                 res = collect(m1[1])[1]
#                 if (Residue(res) != XAA) # It avoids non standar residues, i.e. PYL
#                     println("\"$(m3[1])\" => '$(Char(Residue(res)))',")
#                 end
#                 m3 = nothing
#                 m1 = nothing
#                 peptide = false
#             end
#         else
#             m3 = nothing
#             m1 = nothing
#             peptide = false
#         end
#     end
# end

const _res2three = [ "ALA", "ARG", "ASN", "ASP", "CYS", "GLN", "GLU", "GLY", "HIS", "ILE",
                     "LEU", "LYS", "MET", "PHE", "PRO", "SER", "THR", "TRP", "TYR", "VAL",
                     "   ", "XAA" ]

"""
This function returns the three letter name of the `Residue`.

```jldoctest
julia> using MIToS.MSA

julia> residue2three(Residue('G'))
"GLY"

```
"""
function residue2three(res::Residue)
    int_res = Int(res)
    if int_res == 21  || !isvalid(res)
        #         GAP
        throw(ErrorException("Residue($(int_res)) has not three letter name."))
    end
    _res2three[int_res]
end

"""
It takes a three letter residue name and returns the corresponding `Residue`.
If the name isn't in the MIToS dictionary, a `XAA` is returned.

```jldoctest
julia> using MIToS.MSA

julia> three2residue("ALA")
A

```
"""
function three2residue(res::String)
    if length(res) == 3
        get(_three2res, uppercase(res), XAA)
    else
        throw(ErrorException("The residue name should have 3 letters."))
    end
end

const _three2res = Dict{String, Residue}(
"00C" => 'C',
"02K" => 'A',
"02L" => 'N',
"03Y" => 'C',
"07O" => 'C',
"08P" => 'C',
"0A0" => 'D',
"0A1" => 'Y',
"0A2" => 'K',
"0A8" => 'C',
"0AA" => 'V',
"0AB" => 'V',
"0AC" => 'G',
"0AF" => 'W',
"0AG" => 'L',
"0AH" => 'S',
"0AK" => 'D',
"0BN" => 'F',
"0CS" => 'A',
"0E5" => 'T',
"0EA" => 'Y',
"0FL" => 'A',
"0NC" => 'A',
"0WZ" => 'Y',
"0Y8" => 'P',
"143" => 'C',
"1OP" => 'Y',
"1PA" => 'F',
"1PI" => 'A',
"1TQ" => 'W',
"1TY" => 'Y',
"1X6" => 'S',
"200" => 'F',
"23F" => 'F',
"26B" => 'T',
"2AG" => 'A',
"2CO" => 'C',
"2FM" => 'M',
"2HF" => 'H',
"2KK" => 'K',
"2KP" => 'K',
"2LU" => 'L',
"2ML" => 'L',
"2MR" => 'R',
"2MT" => 'P',
"2OR" => 'R',
"2QZ" => 'T',
"2R3" => 'Y',
"2TL" => 'T',
"2TY" => 'Y',
"2VA" => 'V',
"2XA" => 'C',
"33X" => 'A',
"3AH" => 'H',
"3CF" => 'F',
"3GA" => 'A',
"3MD" => 'D',
"3NF" => 'Y',
"3QN" => 'K',
"3XH" => 'G',
"4BF" => 'Y',
"4CF" => 'F',
"4CY" => 'M',
"4DP" => 'W',
"4FB" => 'P',
"4FW" => 'W',
"4GJ" => 'C',
"4HT" => 'W',
"4IN" => 'W',
"4PH" => 'F',
"4U7" => 'A',
"56A" => 'H',
"5AB" => 'A',
"5CR" => 'F',
"5CS" => 'C',
"5CT" => 'K',
"5CW" => 'W',
"5HP" => 'E',
"5OW" => 'K',
"5VV" => 'N',
"6CL" => 'K',
"6CW" => 'W',
"6GL" => 'A',
"6HN" => 'K',
"6V1" => 'C',
"6WK" => 'C',
"7JA" => 'I',
"9NE" => 'E',
"9NF" => 'F',
"9NR" => 'R',
"9NV" => 'V',
"A5N" => 'N',
"AA3" => 'A',
"AA4" => 'A',
"AAR" => 'R',
"ABA" => 'A',
"ACB" => 'D',
"ACL" => 'R',
"AEI" => 'D',
"AFA" => 'N',
"AGM" => 'R',
"AGT" => 'C',
"AHB" => 'N',
"AHO" => 'A',
"AHP" => 'A',
"AIB" => 'A',
"AKL" => 'D',
"AKZ" => 'D',
"ALA" => 'A',
"ALC" => 'A',
"ALM" => 'A',
"ALN" => 'A',
"ALO" => 'T',
"ALS" => 'A',
"ALT" => 'A',
"ALV" => 'A',
"ALY" => 'K',
"AN8" => 'A',
"APH" => 'A',
"API" => 'K',
"APK" => 'K',
"AR2" => 'R',
"AR4" => 'E',
"AR7" => 'R',
"ARG" => 'R',
"ARM" => 'R',
"ARO" => 'R',
"AS2" => 'D',
"ASA" => 'D',
"ASB" => 'D',
"ASI" => 'D',
"ASK" => 'D',
"ASL" => 'D',
"ASN" => 'N',
"ASP" => 'D',
"ASQ" => 'D',
"AYA" => 'A',
"AZK" => 'K',
"AZS" => 'S',
"AZY" => 'Y',
"B1F" => 'F',
"B2A" => 'A',
"B2F" => 'F',
"B2I" => 'I',
"B2V" => 'V',
"B3A" => 'A',
"B3D" => 'D',
"B3E" => 'E',
"B3K" => 'K',
"B3S" => 'S',
"B3U" => 'H',
"B3X" => 'N',
"B3Y" => 'Y',
"BB6" => 'C',
"BB7" => 'C',
"BB8" => 'F',
"BB9" => 'C',
"BBC" => 'C',
"BCS" => 'C',
"BFD" => 'D',
"BG1" => 'S',
"BH2" => 'D',
"BHD" => 'D',
"BIF" => 'F',
"BIU" => 'I',
"BL2" => 'L',
"BLE" => 'L',
"BLY" => 'K',
"BMT" => 'T',
"BNN" => 'F',
"BOR" => 'R',
"BPE" => 'C',
"BSE" => 'S',
"BTA" => 'L',
"BTC" => 'C',
"BTR" => 'W',
"BUC" => 'C',
"BUG" => 'V',
"C1X" => 'K',
"C22" => 'A',
"C3Y" => 'C',
"C4R" => 'C',
"C5C" => 'C',
"C6C" => 'C',
"CAF" => 'C',
"CAS" => 'C',
"CAY" => 'C',
"CCL" => 'K',
"CCS" => 'C',
"CEA" => 'C',
"CG6" => 'C',
"CGA" => 'E',
"CGU" => 'E',
"CHP" => 'G',
"CIR" => 'R',
"CLE" => 'L',
"CLG" => 'K',
"CLH" => 'K',
"CME" => 'C',
"CMH" => 'C',
"CML" => 'C',
"CMT" => 'C',
"CR5" => 'G',
"CS0" => 'C',
"CS1" => 'C',
"CS3" => 'C',
"CS4" => 'C',
"CSA" => 'C',
"CSB" => 'C',
"CSD" => 'C',
"CSE" => 'C',
"CSJ" => 'C',
"CSO" => 'C',
"CSP" => 'C',
"CSR" => 'C',
"CSS" => 'C',
"CSU" => 'C',
"CSW" => 'C',
"CSX" => 'C',
"CSZ" => 'C',
"CTE" => 'W',
"CTH" => 'T',
"CWR" => 'S',
"CXM" => 'M',
"CY0" => 'C',
"CY1" => 'C',
"CY3" => 'C',
"CY4" => 'C',
"CYA" => 'C',
"CYD" => 'C',
"CYF" => 'C',
"CYG" => 'C',
"CYJ" => 'K',
"CYM" => 'C',
"CYQ" => 'C',
"CYR" => 'C',
"CYS" => 'C',
"CZ2" => 'C',
"CZZ" => 'C',
"D11" => 'T',
"D3P" => 'G',
"DAB" => 'A',
"DAH" => 'F',
"DAL" => 'A',
"DAR" => 'R',
"DAS" => 'D',
"DBB" => 'T',
"DBS" => 'S',
"DBU" => 'T',
"DBY" => 'Y',
"DBZ" => 'A',
"DC2" => 'C',
"DCY" => 'C',
"DDE" => 'H',
"DGH" => 'G',
"DGL" => 'E',
"DGN" => 'Q',
"DHA" => 'S',
"DHI" => 'H',
"DHN" => 'V',
"DHV" => 'V',
"DI7" => 'Y',
"DIL" => 'I',
"DIR" => 'R',
"DIV" => 'V',
"DLE" => 'L',
"DLS" => 'K',
"DLY" => 'K',
"DM0" => 'K',
"DMH" => 'N',
"DMK" => 'D',
"DNE" => 'L',
"DNL" => 'K',
"DNP" => 'A',
"DNS" => 'K',
"DOH" => 'D',
"DON" => 'L',
"DPL" => 'P',
"DPN" => 'F',
"DPP" => 'A',
"DPQ" => 'Y',
"DPR" => 'P',
"DSE" => 'S',
"DSG" => 'N',
"DSN" => 'S',
"DSP" => 'D',
"DTH" => 'T',
"DTR" => 'W',
"DTY" => 'Y',
"DVA" => 'V',
"DYS" => 'C',
"ECC" => 'Q',
"EFC" => 'C',
"EHP" => 'F',
"ESB" => 'Y',
"ESC" => 'M',
"EXY" => 'L',
"F2F" => 'F',
"FAK" => 'K',
"FB5" => 'A',
"FB6" => 'A',
"FCL" => 'F',
"FGA" => 'E',
"FGL" => 'G',
"FGP" => 'S',
"FH7" => 'K',
"FHL" => 'K',
"FHO" => 'K',
"FLA" => 'A',
"FLE" => 'L',
"FLT" => 'Y',
"FME" => 'M',
"FOE" => 'C',
"FP9" => 'P',
"FT6" => 'W',
"FTR" => 'W',
"FTY" => 'Y',
"FVA" => 'V',
"FZN" => 'K',
"GAU" => 'E',
"GFT" => 'S',
"GGL" => 'E',
"GHG" => 'Q',
"GHP" => 'G',
"GL3" => 'G',
"GLH" => 'Q',
"GLJ" => 'E',
"GLK" => 'E',
"GLN" => 'Q',
"GLQ" => 'E',
"GLU" => 'E',
"GLY" => 'G',
"GLZ" => 'G',
"GMA" => 'E',
"GPL" => 'K',
"GSC" => 'G',
"GSU" => 'E',
"GT9" => 'C',
"GVL" => 'S',
"H14" => 'F',
"H5M" => 'P',
"HAC" => 'A',
"HAR" => 'R',
"HBN" => 'H',
"HHI" => 'H',
"HIA" => 'H',
"HIC" => 'H',
"HIP" => 'H',
"HIQ" => 'H',
"HIS" => 'H',
"HL2" => 'L',
"HLU" => 'L',
"HMR" => 'R',
"HPC" => 'F',
"HPE" => 'F',
"HPH" => 'F',
"HPQ" => 'F',
"HQA" => 'A',
"HRG" => 'R',
"HRP" => 'W',
"HS8" => 'H',
"HS9" => 'H',
"HSE" => 'S',
"HSL" => 'S',
"HSO" => 'H',
"HSV" => 'H',
"HTI" => 'C',
"HTN" => 'N',
"HTR" => 'W',
"HV5" => 'A',
"HVA" => 'V',
"HY3" => 'P',
"HYP" => 'P',
"HZP" => 'P',
"I2M" => 'I',
"I58" => 'K',
"IAM" => 'A',
"IAR" => 'R',
"IAS" => 'D',
"IEL" => 'K',
"IGL" => 'G',
"IIL" => 'I',
"ILE" => 'I',
"ILG" => 'E',
"ILX" => 'I',
"IML" => 'I',
"IOY" => 'F',
"IPG" => 'G',
"IT1" => 'K',
"IYR" => 'Y',
"IYT" => 'T',
"IZO" => 'M',
"JJJ" => 'C',
"JJK" => 'C',
"JJL" => 'C',
"K1R" => 'C',
"KCX" => 'K',
"KGC" => 'K',
"KNB" => 'A',
"KOR" => 'M',
"KPF" => 'K',
"KPI" => 'K',
"KST" => 'K',
"KYN" => 'W',
"KYQ" => 'K',
"LA2" => 'K',
"LAA" => 'D',
"LAL" => 'A',
"LBY" => 'K',
"LCK" => 'K',
"LCX" => 'K',
"LDH" => 'K',
"LED" => 'L',
"LEF" => 'L',
"LEH" => 'L',
"LEI" => 'V',
"LEM" => 'L',
"LEN" => 'L',
"LET" => 'K',
"LEU" => 'L',
"LEX" => 'L',
"LLP" => 'K',
"LLY" => 'K',
"LME" => 'E',
"LMF" => 'K',
"LMQ" => 'Q',
"LP6" => 'K',
"LPD" => 'P',
"LPG" => 'G',
"LPS" => 'S',
"LSO" => 'K',
"LTR" => 'W',
"LVG" => 'G',
"LVN" => 'V',
"LYF" => 'K',
"LYK" => 'K',
"LYM" => 'K',
"LYN" => 'K',
"LYR" => 'K',
"LYS" => 'K',
"LYX" => 'K',
"LYZ" => 'K',
"M0H" => 'C',
"M2L" => 'K',
"M2S" => 'M',
"M30" => 'G',
"M3L" => 'K',
"MAA" => 'A',
"MAI" => 'R',
"MBQ" => 'Y',
"MC1" => 'S',
"MCL" => 'K',
"MCS" => 'C',
"MD3" => 'C',
"MD6" => 'G',
"MDF" => 'Y',
"MEA" => 'F',
"MED" => 'M',
"MEG" => 'E',
"MEN" => 'N',
"MEQ" => 'Q',
"MET" => 'M',
"MEU" => 'G',
"MGG" => 'R',
"MGN" => 'Q',
"MGY" => 'G',
"MHL" => 'L',
"MHO" => 'M',
"MHS" => 'H',
"MIS" => 'S',
"MK8" => 'L',
"ML3" => 'K',
"MLE" => 'L',
"MLL" => 'L',
"MLY" => 'K',
"MLZ" => 'K',
"MME" => 'M',
"MMO" => 'R',
"MND" => 'N',
"MNL" => 'L',
"MNV" => 'V',
"MP8" => 'P',
"MPQ" => 'G',
"MSA" => 'G',
"MSE" => 'M',
"MSL" => 'M',
"MSO" => 'M',
"MT2" => 'M',
"MTY" => 'Y',
"MVA" => 'V',
"N10" => 'S',
"N7P" => 'P',
"N80" => 'P',
"N8P" => 'P',
"NA8" => 'A',
"NAL" => 'A',
"NAM" => 'A',
"NB8" => 'N',
"NBQ" => 'Y',
"NC1" => 'S',
"NCB" => 'A',
"NDF" => 'F',
"NEM" => 'H',
"NEP" => 'H',
"NFA" => 'F',
"NHL" => 'E',
"NIY" => 'Y',
"NLE" => 'L',
"NLN" => 'L',
"NLO" => 'L',
"NLP" => 'L',
"NLQ" => 'Q',
"NLW" => 'L',
"NMC" => 'G',
"NMM" => 'R',
"NNH" => 'R',
"NPH" => 'C',
"NPI" => 'A',
"NTR" => 'Y',
"NTY" => 'Y',
"NVA" => 'V',
"NYS" => 'C',
"NZH" => 'H',
"OAR" => 'R',
"OAS" => 'S',
"OBS" => 'K',
"OCS" => 'C',
"OCY" => 'C',
"OHI" => 'H',
"OHS" => 'D',
"OLT" => 'T',
"OLZ" => 'S',
"OMT" => 'M',
"ONH" => 'A',
"OPR" => 'R',
"ORN" => 'A',
"ORQ" => 'R',
"OSE" => 'S',
"OTH" => 'T',
"OXX" => 'D',
"P1L" => 'C',
"P2Y" => 'P',
"PAQ" => 'Y',
"PAS" => 'D',
"PAT" => 'W',
"PAU" => 'A',
"PBB" => 'C',
"PBF" => 'F',
"PCA" => 'E',
"PCC" => 'P',
"PCS" => 'F',
"PEC" => 'C',
"PF5" => 'F',
"PFF" => 'F',
"PG1" => 'S',
"PG9" => 'G',
"PGY" => 'G',
"PH6" => 'P',
"PHA" => 'F',
"PHD" => 'D',
"PHE" => 'F',
"PHI" => 'F',
"PHL" => 'F',
"PHM" => 'F',
"PLE" => 'L',
"PM3" => 'F',
"POM" => 'P',
"PPN" => 'F',
"PR3" => 'C',
"PR9" => 'P',
"PRO" => 'P',
"PRS" => 'P',
"PSA" => 'F',
"PSH" => 'H',
"PTH" => 'Y',
"PTM" => 'Y',
"PTR" => 'Y',
"PVH" => 'H',
"PYA" => 'A',
"PYX" => 'C',
"QCS" => 'C',
"QMM" => 'Q',
"QPA" => 'C',
"QPH" => 'F',
"R1A" => 'C',
"R4K" => 'W',
"RE0" => 'W',
"RE3" => 'W',
"RPI" => 'R',
"RVX" => 'S',
"RZ4" => 'S',
"S1H" => 'S',
"S2C" => 'C',
"S2D" => 'A',
"S2P" => 'A',
"SAC" => 'S',
"SAH" => 'C',
"SAR" => 'G',
"SBL" => 'S',
"SCH" => 'C',
"SCS" => 'C',
"SCY" => 'C',
"SDP" => 'S',
"SE7" => 'A',
"SEB" => 'S',
"SEG" => 'A',
"SEL" => 'S',
"SEM" => 'S',
"SEN" => 'S',
"SEP" => 'S',
"SER" => 'S',
"SET" => 'S',
"SGB" => 'S',
"SHC" => 'C',
"SHP" => 'G',
"SHR" => 'K',
"SIB" => 'C',
"SLR" => 'P',
"SLZ" => 'K',
"SMC" => 'C',
"SME" => 'M',
"SMF" => 'F',
"SNC" => 'C',
"SNN" => 'N',
"SOC" => 'C',
"SOY" => 'S',
"SRZ" => 'S',
"STY" => 'Y',
"SUN" => 'S',
"SVA" => 'S',
"SVV" => 'S',
"SVW" => 'S',
"SVX" => 'S',
"SVY" => 'S',
"SVZ" => 'S',
"SYS" => 'C',
"T11" => 'F',
"TAV" => 'D',
"TBG" => 'V',
"TBM" => 'T',
"TCQ" => 'Y',
"TCR" => 'W',
"TDD" => 'L',
"TFQ" => 'F',
"TH6" => 'T',
"THC" => 'T',
"THR" => 'T',
"THZ" => 'R',
"TIH" => 'A',
"TMB" => 'T',
"TMD" => 'T',
"TNB" => 'C',
"TNR" => 'S',
"TOQ" => 'W',
"TPL" => 'W',
"TPO" => 'T',
"TPQ" => 'Y',
"TQI" => 'W',
"TQQ" => 'W',
"TRF" => 'W',
"TRG" => 'K',
"TRN" => 'W',
"TRO" => 'W',
"TRP" => 'W',
"TRQ" => 'W',
"TRW" => 'W',
"TRX" => 'W',
"TRY" => 'W',
"TTQ" => 'W',
"TTS" => 'Y',
"TXY" => 'Y',
"TY1" => 'Y',
"TY2" => 'Y',
"TY3" => 'Y',
"TY5" => 'Y',
"TYB" => 'Y',
"TYI" => 'Y',
"TYJ" => 'Y',
"TYN" => 'Y',
"TYO" => 'Y',
"TYQ" => 'Y',
"TYR" => 'Y',
"TYS" => 'Y',
"TYT" => 'Y',
"TYW" => 'Y',
"TYY" => 'Y',
"UMA" => 'A',
"VAD" => 'V',
"VAF" => 'V',
"VAL" => 'V',
"VB1" => 'K',
"WLU" => 'L',
"WPA" => 'F',
"WRP" => 'W',
"WVL" => 'V',
"X2W" => 'E',
"XCN" => 'C',
"XDT" => 'T',
"XPR" => 'P',
"XSN" => 'N',
"XX1" => 'K',
"YCM" => 'C',
"YOF" => 'Y',
"YTH" => 'T',
"Z01" => 'A',
"ZAL" => 'A',
"ZCL" => 'F',
"ZU0" => 'T',
"ZZJ" => 'A'
)
