///////////////////////////////////////////////////////////
// SearchResultListRI.cs
// Implementation of Class SearchResultListRI
// CSLA type: Read only collection
// Created on: 01-Oct-2014
// Object design: John
// Coded: 01-Oct-2014
///////////////////////////////////////////////////////////
using System;
using System.Data;
using GZTW.Data;
using CSLA.Data;
using CSLA;
using System.Text;
using System.Collections.Generic;
//using log4net;
namespace GZTW.AyaNova.BLL
{
///
/// Read only collection of objects
///
[Serializable]
public class SearchResultListRI : ReadOnlyCollectionBase
{
#region Data structure
///
///
///
[Serializable]
public struct SearchResultListRIInfo
{
internal Guid mRootObjectID;
internal RootObjectTypes mRootObjectType;
internal Guid mAncestorRootObjectID;
internal RootObjectTypes mAncestorRootObjectType;
internal string mExtract;
internal string mDescription;
internal float mRank;
internal GridNameValueCellItem mSource;
//Public properties
///
/// Object id most closely associated with search result (may not be a directly openable object, that's what ancestor style is for)
///
[Display(DisplayType.Hidden)]
public Guid RootObjectID { get { return mRootObjectID; } }
///
/// Object type most closely associated with search result
///
[Display(DisplayType.Hidden)]
public RootObjectTypes RootObjectType { get { return mRootObjectType; } }
///
/// Object to open to view this search results original record
/// If this object is not a child or grandchild, then this is the same as RootObjectID
///
[Display(DisplayType.Hidden)]
public Guid AncestorRootObjectID { get { return mAncestorRootObjectID; } }
///
/// Object type to open to view this search results original record
///
[Display(DisplayType.Hidden)]
public RootObjectTypes AncestorRootObjectType { get { return mAncestorRootObjectType; } }
///
/// A brief excerpt automatically generated that tries to show the most relevant block of text
/// in the search result for the given search string
///
[Display(DisplayType.Text)]
public string LT_SearchResult_Label_Extract { get { return mExtract; } }
///
/// Description of search result
///
[Display(DisplayType.Text)]
public string LT_SearchResult_Label_Description { get { return mDescription; } }
///
/// Ranking of search result in order of how closely it matches the searched for string of text
/// See class for an explanation of this value
///
[Display(DisplayType.DecimalNumber)]
public float LT_SearchResult_Label_Rank { get { return mRank; } }
internal SmartDate mCreated;
///
/// Date and time object found that matches was created
///
[Display(DisplayType.DateTime)]
public object LT_Common_Label_Created { get { return mCreated.DBValue; } }
internal SmartDate mModified;
///
/// Date and time object found that matches was last modified
///
[Display(DisplayType.DateTime)]
public object LT_Common_Label_Modified { get { return mModified.DBValue; } }
//Case 194
//internal Guid mCreator;
//[Display(DisplayType.ListUsers)]
//public Guid LT_Common_Label_Creator {get{return mCreator;}}
//internal Guid mModifier;
//[Display(DisplayType.ListUsers)]
//public Guid LT_Common_Label_Modifier {get{return mModifier;}}
internal string mCreator;
///
/// Creator of matching found object record
///
[Display(DisplayType.Text)]
public string LT_Common_Label_Creator { get { return mCreator; } }
internal string mModifier;
///
/// Modifier of matching found object record
///
[Display(DisplayType.Text)]
public string LT_Common_Label_Modifier { get { return mModifier; } }
///
/// Descriptive text and id of openable item to view source of search result
/// (used to create search result list buttons in AyaNova UI)
///
[Display(DisplayType.Button, RootObjectType = RootObjectTypes.SearchResult)]
public GridNameValueCellItem LT_SearchResult_Label_Source
{
get
{
return mSource;
}
}
///
///
///
///
public bool Equals(SearchResultListRIInfo obj)
{
return this.mRootObjectID.Equals(obj.mRootObjectID);
}
}//end SearchResultListRIInfo
#endregion
#region Constructor
///
///
///
protected SearchResultListRI()
{
////case 1039 //log.Debug("SearchResultListRI()");
// AllowSort=false;
// AllowFind=true;
// AllowEdit=false;
// AllowNew=false;
// AllowRemove=false;
}
#endregion
#region Business properties and methods
///
/// Get item by index
///
///
public SearchResultListRIInfo this[int Item]
{
get
{
return (SearchResultListRIInfo)List[Item];
}
}
///
/// Returns SearchResultListRIInfo item that matches passed in itemid value
///
///
public SearchResultListRIInfo this[Guid ItemID]
{
get
{
foreach (SearchResultListRIInfo child in List)
{
if (child.mRootObjectID == ItemID) return child;
}
throw new ArgumentException("SearchResultListRI: ID not found:\r\n" + ItemID.ToString());
}
}
#endregion
#region contains
///
/// Check if item in collection
///
///
public bool Contains(SearchResultListRIInfo obj)
{
foreach (SearchResultListRIInfo child in List)
{
if (child.Equals(obj)) return true;
}
return false;
}
#endregion
#region Static methods
///
/// Responsive interface search list
///
///
///
///
public static SearchResultListRI GetList(string Search, int MaxRecords = -1)
{
////case 1039 //log.Debug("GetList("+Search+")");
//if empty search return empty list
if (Search == null) return new SearchResultListRI();
if (Search == "") return new SearchResultListRI();
//scrub search string for sql injection attacks
//and pass to fetch through criteria
return (SearchResultListRI)DataPortal.Fetch(new Criteria(Search.Replace("\"", ""), MaxRecords));
}
#endregion
#region DAL DATA ACCESS
///
///
protected override void DataPortal_Fetch(object Criteria)
{
Criteria crit = (Criteria)Criteria;
if (crit.Search == "") return;
crit.Search = crit.Search.Replace("*", "%");
string[] saTerms = AyaBizUtils.BreakSearchPhrase(crit.Search).Split(',');
if (saTerms == null || saTerms.GetLength(0) == 0) return;
//Case 194
UserPickList upl = null;
upl = UserPickList.GetList(false);
#region Numeric only search
//If it's only digits optimize search for auto numbered items (workorder, quote, pm, PO, Inventory adjustment (but probably not that one))
if (AyaBizUtils.DigitsOnly(crit.Search))
{
Guid serviceId = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString(
"SELECT AWORKORDER.AID " +
"FROM AWORKORDER " +
"INNER JOIN AWORKORDERSERVICE ON (AWORKORDER.AID = AWORKORDERSERVICE.AWORKORDERID) " +
"WHERE AWORKORDERSERVICE.ASERVICENUMBER = " + crit.Search +
"AND AWORKORDER.AWORKORDERTYPE = 1 "
));//"SELECT AWORKORDERID FROM AWORKORDERSERVICE WHERE ASERVICENUMBER = " + crit.Search
Guid quoteId = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString(
"SELECT AWORKORDERQUOTE.AID " +
"FROM AWORKORDER " +
"INNER JOIN AWORKORDERQUOTE ON (AWORKORDER.AID = AWORKORDERQUOTE.AWORKORDERID) " +
"WHERE AWORKORDERQUOTE.AQUOTENUMBER = " + crit.Search +
"AND AWORKORDER.AWORKORDERTYPE = 3 "
//"SELECT AWORKORDERID FROM AWORKORDERQUOTE WHERE AQUOTENUMBER = " + crit.Search
));
Guid pmId = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString(
"SELECT AWORKORDERPREVENTIVEMAINTENANCE.AID " +
"FROM AWORKORDER " +
"INNER JOIN AWORKORDERPREVENTIVEMAINTENANCE ON (AWORKORDER.AID = AWORKORDERPREVENTIVEMAINTENANCE.AWORKORDERID) " +
"WHERE AWORKORDERPREVENTIVEMAINTENANCE.APREVENTIVEMAINTENANCENUMBER = " + crit.Search +
"AND AWORKORDER.AWORKORDERTYPE = 2 "
// "SELECT AWORKORDERID FROM AWORKORDERPREVENTIVEMAINTENANCE WHERE APREVENTIVEMAINTENANCENUMBER = " + crit.Search
));
Guid poId = DBUtil.ToGuid(DBUtil.GetScalarFromSQLString("SELECT AID FROM APURCHASEORDER WHERE APONUMBER = " + crit.Search));
AddNumericHit(RootObjectTypes.Workorder, serviceId, saTerms, upl);
// AddNumericHit(RootObjectTypes.Workorder, quoteId, saTerms, upl);
// AddNumericHit(RootObjectTypes.Workorder, pmId, saTerms, upl);
AddNumericHit(RootObjectTypes.WorkorderQuote, quoteId, saTerms, upl);
AddNumericHit(RootObjectTypes.WorkorderPreventiveMaintenance, pmId, saTerms, upl);
AddNumericHit(RootObjectTypes.PurchaseOrder, poId, saTerms, upl);
}
#endregion numeric search
#region natural search
//sql ize it
// crit.Search = crit.Search.Replace("*", "%");
StringBuilder sbSQL = new StringBuilder();
//convert search terms to query
string q = "SELECT ~MAXRECS~ aSearchKey.aSourceObjectID, aSearchKey.aSourceObjectType " +
"FROM aSearchDictionary INNER " +
"JOIN aSearchKey ON aSearchDictionary.aID " +
"= aSearchKey.aWordID WHERE ";
if (crit.MaxRecords > 0)
q = q.Replace("~MAXRECS~", "TOP " + crit.MaxRecords.ToString());
else
q = q.Replace("~MAXRECS~", "");
sbSQL.Append(q);
//case 3581
string insertNationalTypeQueryCharacter = string.Empty;
if (DBUtil.DB.DBType == DataBaseType.MSSQL)
{
insertNationalTypeQueryCharacter = "N";
}
foreach (string sTerm in saTerms)
{
if (sTerm.IndexOf("%") != -1)
sbSQL.Append(" (aSearchDictionary.aWord Like " + insertNationalTypeQueryCharacter + "'" + sTerm + "') OR");//case 3581
else
sbSQL.Append(" (aSearchDictionary.aWord = " + insertNationalTypeQueryCharacter + "'" + sTerm + "') OR");//case 3581
}
//trim off the final "OR"
sbSQL.Length = sbSQL.Length - 2;
sbSQL.Append(" GROUP BY aSearchKey.aSourceObjectID, " +
"aSearchKey.aSourceObjectType HAVING (COUNT(*) " +
"= " + saTerms.GetLength(0).ToString() + ")");
//------------------
SafeDataReader dr = null;
try
{
dr = DBUtil.GetReaderFromSQLString(sbSQL.ToString());
while (dr.Read())
{
//standard search
SearchResult sr = AyaBizUtils.GetSearchResultFor((RootObjectTypes)dr.GetInt16("aSourceObjectType"), dr.GetGuid("aSourceObjectID"), saTerms);
//sr.rank will equal zero if there is no good match or
//if the user has no rights to retrieve that object etc
if (sr.Rank > 0)
{
sr = MarkTerms(sr, saTerms);
SearchResultListRIInfo info = new SearchResultListRIInfo();
info.mRootObjectID = dr.GetGuid("aSourceObjectID");
info.mRootObjectType = (RootObjectTypes)dr.GetInt16("aSourceObjectType");
info.mAncestorRootObjectID = sr.AncestorRootObjectID;
info.mAncestorRootObjectType = sr.AncestorRootObjectType;
info.mDescription = sr.Description;
info.mExtract = sr.Extract;
info.mRank = sr.Rank;
info.mModified = sr.Modified;
info.mModifier = upl[sr.Modifier];
info.mCreated = sr.Created;
info.mCreator = upl[sr.Creator];
info.mSource = new GridNameValueCellItem(
info.mAncestorRootObjectID,
EnumDescConverter.GetEnumDescription(info.mRootObjectType),
info.mAncestorRootObjectType);
InnerList.Add(info);
}
}
}
finally
{
if (dr != null) dr.Close();
}
#endregion natural
}
private SearchResult MarkTerms(SearchResult sr, string [] terms)
{
foreach (string s in terms)
{
sr.Extract=sr.Extract.Replace(s, "" + s + "");
}
return sr;
}
private void AddNumericHit(RootObjectTypes roType, Guid id, string[] term, UserPickList upl)
{
//bugbug: quote, pm not showing description nor extract. PO is only showing vendor name in extract.
if (id == Guid.Empty) return;
RootObjectTypes srType = roType;
//it appears that search result doesn't work with specific subtypes of workorders only the workorder type itself
//if (roType == RootObjectTypes.WorkorderQuote || roType == RootObjectTypes.WorkorderPreventiveMaintenance)
// srType = RootObjectTypes.Workorder;
SearchResult sr = AyaBizUtils.GetSearchResultFor(srType, id, term);
//description should only be if the user has no rights or not in region
if (null==sr.Description) return;
sr = MarkTerms(sr, term);
SearchResultListRIInfo info = new SearchResultListRIInfo();
info.mAncestorRootObjectID = info.mRootObjectID = id;
info.mAncestorRootObjectType = info.mRootObjectType = roType;
info.mDescription = sr.Description;
info.mExtract = sr.Extract;
// since this is a direct hit based on the number and the user typed in only the number it should rank super high
info.mRank = 99;
info.mModified = sr.Modified;
info.mModifier = upl[sr.Modifier];
info.mCreated = sr.Created;
info.mCreator = upl[sr.Creator];
info.mSource = new GridNameValueCellItem(
info.mAncestorRootObjectID,
EnumDescConverter.GetEnumDescription(info.mRootObjectType) + " - " + term[0],
info.mAncestorRootObjectType);
InnerList.Add(info);
}
#endregion
#region criteria
///
/// Criteria for identifying existing object
///
[Serializable]
private class Criteria
{
public string Search;
public int MaxRecords;
public Criteria(string _Search, int _MaxRecords)
{
Search = _Search;
MaxRecords = _MaxRecords;
}
}
#endregion
}//end SearchResultListRI
}//end namespace GZTW.AyaNova.BLL