
use strict;
use warnings;
use RT;
use RT::Test tests => undef;
use Test::Warn;

use_ok('RT::CustomField');

my $queue = RT::Queue->new( RT->SystemUser );
$queue->Load( "General" );
ok( $queue->id, "found the General queue" );

my $cf = RT::CustomField->new(RT->SystemUser);
ok($cf, "Have a CustomField object");

# Use the old Queue field to set up a ticket CF
my ($ok, $msg) =  $cf->Create(
    Name        => 'TestingCF',
    Queue       => '0',
    Description => 'A Testing custom field',
    Type        => 'SelectSingle'
);
ok($ok, 'Global custom field correctly created');
is($cf->Type, 'Select', "Is a select CF");
ok($cf->SingleValue, "Also a single-value CF");
is($cf->MaxValues, 1, "...meaning only one value, max");

($ok, $msg) = $cf->SetMaxValues('0');
ok($ok, "Set to infinite values: $msg");
is($cf->Type, 'Select', "Still a select CF");
ok( ! $cf->SingleValue, "No longer single-value" );
is($cf->MaxValues, 0, "...meaning no maximum values");

# Test our sanity checking of CF types
($ok, $msg) = $cf->SetType('BogusType');
ok( ! $ok, "Unable to set a custom field's type to a bogus type: $msg");

$cf = RT::CustomField->new(RT->SystemUser);
($ok, $msg) = $cf->Create(
    Name => 'TestingCF-bad',
    Queue => '0',
    SortOrder => '1',
    Description => 'A Testing custom field with a bogus Type',
    Type=> 'SelectSingleton'
);
ok( ! $ok, "Correctly could not create with bogus type: $msg");


# Deprecated types
warning_like {
    ok($cf->ValidateType('SelectSingle'), "ValidateType accepts SelectSingle");
} qr/deprecated/, "...but warns of deprecation";

warning_like {
    ok($cf->ValidateType('SelectMultiple'), "ValidateType accepts SelectMultiple");
} qr/deprecated/, "...but warns of deprecation";

warning_like {
    ok( ! $cf->ValidateType('SelectFooMultiple'), "ValidateType does not accept SelectFooMultiple");
} qr/deprecated/, "...and also warns of deprecation";


# Test adding and removing CFVs
$cf->Load(1);
($ok, $msg) = $cf->AddValue(Name => 'foo' , Description => 'TestCFValue', SortOrder => '6');
ok($ok, "Added a new value to the select options");
($ok, $msg) = $cf->DeleteValue($ok);
ok($ok, "Deleting it again");


# Loading, and context objects
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName( Name => "TestingCF" );
ok($cf->id, "Load finds it, given just a name" );
ok( ! $cf->ContextObject, "Did not get a context object");

# Old Queue => form should find the global, gain no context object
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0);
ok($cf->id, "Load finds it, given a Name and Queue => 0" );
ok( ! $cf->ContextObject, 'Context object not set when queue is 0');

# We don't default to also searching global -- but do pick up a contextobject
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1);
ok( ! $cf->id, "Load does not finds it, given a Name and Queue => 1" );
ok($cf->ContextObject->id, 'Context object is now set');

# If we IncludeGlobal, we find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1, IncludeGlobal => 1 );
ok($cf->id, "Load now finds it, given a Name and Queue => 1 and IncludeGlobal" );
ok($cf->ContextObject->id, 'Context object is also set');

# The explicit LookupType works
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType );
ok($cf->id, "Load now finds it, given a Name and LookupType" );
ok( ! $cf->ContextObject, 'No context object gained');

# The explicit LookupType, ObjectId, and IncludeGlobal -- what most folks want
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType,
                ObjectId => 1, IncludeGlobal => 1 );
ok($cf->id, "Load now finds it, given a Name, LookupType, ObjectId, IncludeGlobal" );
ok($cf->ContextObject->id, 'And gains a context obj');

# Look for a queue by name
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => "General" );
ok( ! $cf->id, "No IncludeGlobal, so queue by name fails" );
ok($cf->ContextObject->id, 'But gains a context object');

# Look for a queue by name, include global
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => "General", IncludeGlobal => 1 );
ok($cf->id, "By name, and queue name works with IncludeGlobal" );
ok($cf->ContextObject->id, 'And gains a context object');



# A bogus Queue gets you no results, but a warning
$cf = RT::CustomField->new( RT->SystemUser );
warning_like {
    $cf->LoadByName(Name => 'TestingCF', Queue => "Bogus" );
    ok( ! $cf->id, "With a bogus queue name gets no results" );
    ok( ! $cf->ContextObject, 'And also no context object');
} qr/Failed to load RT::Queue 'Bogus'/, "Generates a warning";

# Ditto by number which is bogus
$cf = RT::CustomField->new( RT->SystemUser );
warning_like {
    $cf->LoadByName(Name => 'TestingCF', Queue => "9000" );
    ok( ! $cf->id, "With a bogus queue number gets no results" );
    ok( ! $cf->ContextObject, 'And also no context object');
} qr/Failed to load RT::Queue '9000'/, "Generates a warning";

# But if they also wanted global results, we might have an answer
$cf = RT::CustomField->new( RT->SystemUser );
warning_like {
    $cf->LoadByName(Name => 'TestingCF', Queue => "9000", IncludeGlobal => 1 );
    ok($cf->id, "Bogus queue but IncludeGlobal founds it" );
    ok( ! $cf->ContextObject, 'But no context object');
} qr/Failed to load RT::Queue '9000'/, "And generates a warning";


# Make it only apply to one queue
$cf->Load(1);
my $ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->LoadByCols( CustomField => $cf->id, ObjectId => 0 );
ok( $ok, "Found global application of CF" );
( $ok, $msg ) = $ocf->Delete;
ok( $ok, "...and deleted it");
( $ok, $msg ) = $ocf->Add( CustomField => $cf->id, ObjectId => 1 );
ok($ok, "Applied to just queue 1" );

# Looking for it globally with Queue => 0 should fail, gain no context object
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0);
ok( ! $cf->id, "Load fails to find, given a Name and Queue => 0" );
ok( ! $cf->ContextObject, 'Context object not set when queue is 0');

# Looking it up by Queue => 1 works fine, and gets context object
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1);
ok($cf->id, "Load does finds it, given a Name and Queue => 1" );
ok($cf->ContextObject->id, 'Context object is now set');

# Also find it with IncludeGlobal
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1, IncludeGlobal => 1 );
ok($cf->id, "Load also finds it, given a Name and Queue => 1 and IncludeGlobal" );
ok($cf->ContextObject->id, 'Context object is also set');

# The explicit LookupType works
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType );
ok($cf->id, "Load also finds it, given a Name and LookupType" );
ok( ! $cf->ContextObject, 'But no context object gained');

# Explicit LookupType, ObjectId works
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType,
                ObjectId => 1 );
ok($cf->id, "Load still finds it, given a Name, LookupType, ObjectId" );
ok($cf->ContextObject->id, 'And gains a context obj');

# Explicit LookupType, ObjectId works
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType,
                ObjectId => 1, IncludeGlobal => 1 );
ok($cf->id, "Load also finds it, given a Name, LookupType, ObjectId, and IncludeGlobal" );
ok($cf->ContextObject->id, 'And gains a context obj');

# Look for a queue by name
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => "General" );
ok($cf->id, "Finds it by queue name" );
ok($cf->ContextObject->id, 'But gains a context object');

# Look for a queue by name, include global
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => "General", IncludeGlobal => 1 );
ok($cf->id, "By name, and queue name works with IncludeGlobal" );
ok($cf->ContextObject->id, 'And gains a context object');




# Change the lookup type to be a _queue_ CF
($ok, $msg) = $cf->SetLookupType( RT::Queue->CustomFieldLookupType );
ok($ok, "Changed CF type to be a CF on queues" );
$ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );

# Just looking by name gets you CFs of any type
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF');
ok($cf->id, "Find the CF by name, with no queue" );

# Queue => 0 means "ticket CF", so doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0);
ok( ! $cf->id, "Wrong lookup type to find with Queue => 0" );

# Queue => 1 and IncludeGlobal also doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0, IncludeGlobal => 1);
ok( ! $cf->id, "Also doesn't find with Queue => 0 and IncludeGlobal" );

# Find it with the right LookupType
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType );
ok($cf->id, "Found for the right lookup type" );

# Found globally
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType, ObjectId => 0 );
ok($cf->id, "Found for the right lookup type and ObjectId 0" );

# Also works with Queue instead of ObjectId
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType, Queue => 0 );
ok($cf->id, "Found for the right lookup type and Queue 0" );

# Not found without IncludeGlobal
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType, ObjectId => 1 );
ok( ! $cf->id, "Not found for ObjectId 1 and no IncludeGlobal" );

# Found with IncludeGlobal
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType,
                ObjectId => 1, IncludeGlobal => 1 );
ok($cf->id, "Found for ObjectId 1 and IncludeGlobal" );

# Found with IncludeGlobal and Queue instead of ObjectId
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Queue->CustomFieldLookupType,
                ObjectId => 1, IncludeGlobal => 1 );
ok($cf->id, "Found for Queue 1 and IncludeGlobal" );



# Change the lookup type to be a _transaction_ CF
($ok, $msg) = $cf->SetLookupType( RT::Transaction->CustomFieldLookupType );
ok($ok, "Changed CF type to be a CF on transactions" );
$ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );

# Just looking by name gets you CFs of any type
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF');
ok($cf->id, "Find the CF by name, with no queue" );

# Queue => 0 means "ticket CF", so doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0);
ok( ! $cf->id, "Wrong lookup type to find with Queue => 0" );

# Queue => 1 and IncludeGlobal also doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0, IncludeGlobal => 1);
ok( ! $cf->id, "Also doesn't find with Queue => 0 and IncludeGlobal" );


# Change the lookup type to be a _user_ CF
$cf->Load(1);
($ok, $msg) = $cf->SetLookupType( RT::User->CustomFieldLookupType );
ok($ok, "Changed CF type to be a CF on users" );
$ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );

# Just looking by name gets you CFs of any type
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF');
ok($cf->id, "Find the CF by name, with no queue" );

# Queue => 0 means "ticket CF", so doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0);
ok( ! $cf->id, "Wrong lookup type to find with Queue => 0" );

# Queue => 1 and IncludeGlobal also doesn't find it
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0, IncludeGlobal => 1);
ok( ! $cf->id, "Also doesn't find with Queue => 0 and IncludeGlobal" );

# But RT::User->CustomFieldLookupType does
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::User->CustomFieldLookupType );
ok($cf->id, "User lookuptype does" );

# Also with an explicit global
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::User->CustomFieldLookupType, ObjectId => 0 );
ok($cf->id, "Also with user CF and explicit global" );



# Add a second, queue-specific CF to test load order
$cf->Load(1);
($ok, $msg) = $cf->SetLookupType( RT::Ticket->CustomFieldLookupType );
ok($ok, "Changed CF type back to be a CF on tickets" );
$ocf = RT::ObjectCustomField->new( RT->SystemUser );
( $ok, $msg ) = $ocf->Add( CustomField => $cf->id, ObjectId => 0 );
ok($ok, "Applied globally" );
($ok, $msg) = $cf->SetDescription( "Global CF" );
ok($ok, "Changed CF type back to be a CF on tickets" );

($ok, $msg) = $cf->Create(
    Name        => 'TestingCF',
    Queue       => '1',
    Description => 'Queue-specific CF',
    Type        => 'SelectSingle'
);
ok($ok, "Created second CF successfully");

# If passed just a name, you get the first by id
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF' );
like($cf->Description, qr/Global/, "Gets the first (global) one if just loading by name" );

# Ditto if also limited to lookuptype
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', LookupType => RT::Ticket->CustomFieldLookupType );
like($cf->Description, qr/Global/, "Same, if one adds a LookupType" );

# Gets the global with Queue => 0
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 0 );
like($cf->Description, qr/Global/, "Specify Queue => 0 and get global" );

# Gets the queue with Queue => 1
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1 );
like($cf->Description, qr/Queue/, "Specify Queue => 1 and get the queue" );

# Gets the queue with Queue => 1 and IncludeGlobal
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1, IncludeGlobal => 1 );
like($cf->Description, qr/Queue/, "Specify Queue => 1 and IncludeGlobal and get the queue" );


# Disable one of them
($ok, $msg) = $cf->SetDisabled(1);
ok($ok, "Disabled the Queue-specific one");

# With just a name, prefers the non-disabled
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF' );
like($cf->Description, qr/Global/, "Prefers non-disabled CFs" );

# Still finds the queue one, if asked
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1 );
like($cf->Description, qr/Queue/, "Still loads the disabled queue CF" );

# Prefers the global one if IncludeGlobal
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1, IncludeGlobal => 1 );
like($cf->Description, qr/Global/, "Prefers the global one with IncludeGlobal" );

# IncludeDisabled allows filtering out the disabled one
$cf = RT::CustomField->new( RT->SystemUser );
$cf->LoadByName(Name => 'TestingCF', Queue => 1, IncludeDisabled => 0 );
ok( ! $cf->id, "Doesn't find it if IncludeDisabled => 0" );


done_testing;
